关于 query-generation
query-generation 是一项 ServiceNow 技能,可将自然语言数据需求转为编码查询、GlideRecord 和 GlideAggregate 脚本及报表筛选条件。它面向检索记录或配置报表的用户,涵盖日期逻辑、AND/OR 条件和关联表字段。
主要功能
- 01自然语言转编码查询
- 02GlideRecord 查询脚本
- 03GlideAggregate 汇总
- 04报表筛选条件配置
- 05日期与相对时间筛选
- 06AND/OR 及点遍历查询
适用场景
- 01按自然语言需求筛选事件列表
- 02按类别或优先级汇总记录
- 03配置 ServiceNow 报表条件
- 04使用日期范围和关联字段构建查询
MCP 相关
该技能介绍使用 MCP 工具 SN-Create-Record 创建 ServiceNow 报表,也提供通过 MCP 查询 ServiceNow 数据的示例。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ happy-technologies-llc/ happy-platform-skills --skill query-generation安装后在 Claude Code 中输入/query-generation确认已加载。
详细介绍
从自然语言生成 ServiceNow 查询
概述
此技能涵盖将自然语言描述转换为 ServiceNow 查询、脚本和报表配置:
- 将简单的英文需求转换为编码查询
- 使用正确的过滤运算符构建 GlideRecord 查询
- 生成用于数据汇总的 GlideAggregate 脚本
- 为仪表板创建报表筛选条件
- 转换包含 AND/OR 逻辑的复杂多条件查询
- 生成基于日期、相对时间和动态查询的查询
适用场景: 用户以自然语言描述数据需求、构建报表筛选条件、创建基于脚本的数据检索,或为列表和模块构建复杂编码查询时。
前提条件
- 角色:
itil、report_user、admin,或任何可读取目标表的角色 - 访问权限: 目标数据表、用于字段验证的 sys_dictionary、用于创建报表的 sys_report
- 知识: ServiceNow 编码查询语法、GlideRecord API、GlideAggregate API、数据类型
- 相关技能: 完成
reporting/analytics-generation以创建仪表板
流程
第 1 步:了解编码查询语法
ServiceNow 编码查询使用特定语法筛选记录:
运算符参考:
| 运算符 | 语法 | 示例 |
|---|---|---|
| 等于 | = | priority=1 |
| 不等于 | != | state!=6 |
| 包含 | LIKE | short_descriptionLIKEnetwork |
| 不包含 | NOT LIKE | short_descriptionNOT LIKEtest |
| 以……开头 | STARTSWITH | numberSTARTSWITHINC |
| 以……结尾 | ENDSWITH | [email protected] |
| 为空 | ISEMPTY | assignment_groupISEMPTY |
| 不为空 | ISNOTEMPTY | resolved_atISNOTEMPTY |
| 大于 | > | priority>2 |
| 小于 | < | priority<3 |
| 大于或等于 | >= | sys_created_on>=2025-01-01 |
| 小于或等于 | <= | sys_created_on<=2025-12-31 |
| 在列表中 | IN | state IN 1,2,3 |
| 不在列表中 | NOT IN | priority NOT IN 4,5 |
| 介于 | BETWEEN | sys_created_onBETWEEN2025-01-01@2025-06-30 |
| 实例属于 | INSTANCEOF | sys_class_nameINSTANCEOFtask |
| AND | ^ | active=true^priority=1 |
| OR | ^OR | priority=1^ORpriority=2 |
| 新查询(OR 组) | ^NQ | priority=1^NQstate=6 |
日期运算符:
| 函数 | 语法 | 含义 |
|---|---|---|
| 今天 | javascript:gs.daysAgo(0) | 当前日期 |
| 过去 7 天 | javascript:gs.daysAgo(7) | 过去一周 |
| 过去 30 天 | javascript:gs.daysAgo(30) | 过去一个月 |
| 本月开始 | javascript:gs.beginningOfThisMonth() | 本月第一天 |
| 本季度开始 | javascript:gs.beginningOfThisQuarter() | 本季度第一天 |
| 今年开始 | javascript:gs.beginningOfThisYear() | 今年第一天 |
| 上月开始 | javascript:gs.beginningOfLastMonth() | 上个月第一天 |
| 上月结束 | javascript:gs.endOfLastMonth() | 上个月最后一天 |
第 2 步:将自然语言转换为编码查询
自然语言转换为查询的示例:
| 自然语言 | 编码查询 |
|---|---|
| “所有未关闭的严重事件” | active=true^priority=1 |
| “本周打开、分配给 Service Desk 的事件” | assignment_group.name=Service Desk^sys_created_on>=javascript:gs.daysAgo(7) |
| “未解决的 P1 或 P2 事件” | active=true^priority=1^ORpriority=2 |
| “已批准但尚未实施的变更” | state=authorized^ORstate=scheduled |
| “没有经理的用户” | managerISEMPTY^active=true |
| “2025 年第一季度创建的事件” | sys_created_on>=2025-01-01^sys_created_on<2025-04-01 |
| “3 天内未更新的高优先级事件” | priority IN 1,2^sys_updated_on<javascript:gs.daysAgo(3)^active=true |
第 3 步:根据表架构验证查询
使用查询前,请确认目标表中存在相应字段。
MCP 方式:
Tool: SN-Get-Table-Schema
Parameters:
table_name: incident
REST 替代方案:
curl -u "$SN_USER:$SN_PASS" \
"$SN_INSTANCE/api/now/table/sys_dictionary?sysparm_query=name=incident^elementISNOTEMPTY^active=true&sysparm_fields=element,column_label,internal_type&sysparm_limit=200" \
-H "Accept: application/json"
第 4 步:测试生成的查询
MCP 方式:
Tool: SN-Query-Table
Parameters:
table_name: incident
query: active=true^priority=1^assignment_groupISEMPTY
fields: sys_id,number,short_description,priority,state,sys_created_on
limit: 10
REST 替代方式:
curl -u "$SN_USER:$SN_PASS" \
"$SN_INSTANCE/api/now/table/incident?sysparm_query=active=true^priority=1^assignment_groupISEMPTY&sysparm_fields=sys_id,number,short_description,priority,state&sysparm_limit=10" \
-H "Accept: application/json"
第 5 步:生成 GlideRecord 脚本
基本 GlideRecord 查询:
// Natural Language: "Get all active incidents assigned to the Network team"
var gr = new GlideRecord('incident');
gr.addQuery('active', true);
gr.addQuery('assignment_group.name', 'Network');
gr.orderByDesc('sys_created_on');
gr.setLimit(100);
gr.query();
while (gr.next()) {
gs.info('Incident: {0} - {1} (Priority: {2})',
gr.getValue('number'),
gr.getValue('short_description'),
gr.getDisplayValue('priority'));
}
包含复杂条件的 GlideRecord:
// Natural Language: "Find incidents that are either P1 or P2,
// created in the last 7 days, and not yet assigned"
var gr = new GlideRecord('incident');
var qc = gr.addQuery('priority', '1');
qc.addOrCondition('priority', '2');
gr.addQuery('sys_created_on', '>=', gs.daysAgo(7));
gr.addQuery('assigned_to', '');
gr.addActiveQuery();
gr.query();
gs.info('Found {0} unassigned high-priority incidents', gr.getRowCount());
包含编码查询的 GlideRecord:
// Natural Language: "All resolved incidents from this month
// where the resolution was a workaround"
var gr = new GlideRecord('incident');
gr.addEncodedQuery('state=6^sys_resolved_on>=javascript:gs.beginningOfThisMonth()^close_notesLIKEworkaround');
gr.query();
while (gr.next()) {
gs.info('{0}: {1}', gr.getValue('number'), gr.getValue('close_notes'));
}
第 6 步:生成 GlideAggregate 脚本
分组计数:
// Natural Language: "How many incidents are open per priority?"
var ga = new GlideAggregate('incident');
ga.addQuery('active', true);
ga.addAggregate('COUNT');
ga.groupBy('priority');
ga.orderBy('priority');
ga.query();
while (ga.next()) {
gs.info('Priority {0}: {1} incidents',
ga.getDisplayValue('priority'),
ga.getAggregate('COUNT'));
}
平均值计算:
// Natural Language: "What is the average resolution time by category?"
var ga = new GlideAggregate('incident');
ga.addQuery('state', 6); // Resolved
ga.addQuery('sys_resolved_on', '>=', gs.daysAgo(90));
ga.addAggregate('AVG', 'business_duration');
ga.groupBy('category');
ga.query();
while (ga.next()) {
var avgDuration = ga.getAggregate('AVG', 'business_duration');
var hours = (parseInt(avgDuration, 10) / 3600).toFixed(1);
gs.info('Category: {0} - Avg Resolution: {1} hours',
ga.getDisplayValue('category'), hours);
}
带筛选条件的求和:
// Natural Language: "Total cost of all hardware assets purchased this year"
var ga = new GlideAggregate('alm_hardware');
ga.addQuery('purchase_date', '>=', gs.beginningOfThisYear());
ga.addAggregate('SUM', 'cost');
ga.query();
if (ga.next()) {
gs.info('Total hardware cost this year: ${0}',
ga.getAggregate('SUM', 'cost'));
}
多个聚合:
// Natural Language: "For each assignment group, show count,
// average priority, and oldest open incident"
var ga = new GlideAggregate('incident');
ga.addQuery('active', true);
ga.addAggregate('COUNT');
ga.addAggregate('AVG', 'priority');
ga.addAggregate('MIN', 'sys_created_on');
ga.groupBy('assignment_group');
ga.orderByAggregate('COUNT');
ga.query();
while (ga.next()) {
gs.info('Group: {0} | Count: {1} | Avg Priority: {2} | Oldest: {3}',
ga.getDisplayValue('assignment_group'),
ga.getAggregate('COUNT'),
parseFloat(ga.getAggregate('AVG', 'priority')).toFixed(1),
ga.getAggregate('MIN', 'sys_created_on'));
}
第 7 步:生成报表筛选条件
使用生成的查询创建报表:
MCP 方式:
Tool: SN-Create-Record
Parameters:
table_name: sys_report
data:
title: "Unassigned Critical Incidents"
table: "incident"
type: "list"
filter: "active=true^priority=1^assigned_toISEMPTY"
is_published: true
active: true
使用查询创建图表报表:
MCP 方式:
Tool: SN-Create-Record
Parameters:
table_name: sys_report
data:
title: "Monthly Incident Trend by Priority"
table: "incident"
type: "line"
field: "priority"
filter: "sys_created_on>=javascript:gs.monthsAgo(12)"
aggregate: "COUNT"
trend_field: "sys_created_on"
interval: "month"
is_published: true
active: true
REST 替代方式:
curl -u "$SN_USER:$SN_PASS" \
"$SN_INSTANCE/api/now/table/sys_report" \
-H "Content-Type: application/json" \
-X POST \
-d '{
"title": "Monthly Incident Trend by Priority",
"table": "incident",
"type": "line",
"field": "priority",
"filter": "sys_created_on>=javascript:gs.monthsAgo(12)",
"aggregate": "COUNT",
"trend_field": "sys_created_on",
"interval": "month",
"is_published": true
}'
第 8 步:高级查询模式
点遍历(相关表字段):
// Natural Language: "Incidents where the caller's department is IT"
query: caller_id.department.name=IT^active=true
动态引用限定符:
// Natural Language: "Incidents assigned to the current user's group"
query: assignment_group=javascript:getMyGroups()^active=true
相对日期查询:
// Natural Language: "Changes scheduled for next week"
query: start_date>=javascript:gs.daysAgo(-1)^start_date<javascript:gs.daysAgo(-8)
用于层级查询的 INSTANCEOF:
// Natural Language: "All tasks including incidents, changes, and problems"
query: sys_class_nameINSTANCEOFtask^active=true
工具用法
| 操作 | MCP 工具 | REST 端点 |
|---|---|---|
| 测试查询 | SN-Query-Table | GET /api/now/table/{table}?sysparm_query={query} |
| 获取表结构 | SN-Get-Table-Schema | GET /api/now/table/sys_dictionary |
| 创建报表 | SN-Create-Record | POST /api/now/table/sys_report |
| 创建 PA 指标 | SN-Create-Record | POST /api/now/table/pa_indicators |
| 验证字段 | SN-Query-Table | GET /api/now/table/sys_dictionary |
最佳实践
- 先验证字段: 构建查询前,务必检查 sys_dictionary,确认字段名称
- 逐步测试: 一次添加一个条件来构建复杂查询,并测试每次添加的条件
- 报表优先使用编码查询: 与脚本筛选器相比,编码查询的可移植性更强,也更适合 URL
- 计数优先使用 GlideAggregate 而非 GlideRecord: GlideAggregate 执行聚合的效率高得多
- 测试时使用 setLimit: 开发过程中务必限制结果数量,以避免性能问题
- 谨慎使用点遍历: 跨多个引用进行点遍历可能会影响性能
- 多个值使用 IN 运算符:
priority IN 1,2,3比串联 OR 条件更简洁 - 记录复杂查询: 添加注释,说明多条件查询背后的业务逻辑
- 日期使用 javascript: 函数: 相对日期函数可确保查询保持动态
- 避免在动态查询中使用 eval(): 切勿根据未经验证的用户输入构造查询
- 为关键筛选字段建立索引: 确保常用筛选字段具有数据库索引
故障排查
查询未返回结果
现象: 数据应该存在,但编码查询返回空结果集 原因:
- 字段名称拼写错误,或该字段在表中不存在
- 值不匹配(大小写敏感、显示值与内部值不同)
- ACL 限制筛掉了结果 解决方案: 验证字段名称和值:
Tool: SN-Get-Table-Schema
Parameters:
table_name: [target_table]
然后测试简化版查询:
Tool: SN-Query-Table
Parameters:
table_name: [target_table]
query: [single_condition_only]
fields: sys_id
limit: 1
查询返回过多结果
现象: 查询范围过宽,返回了过多记录 原因:
- 缺少筛选条件
- OR 条件范围过宽
- 缺少 active=true 筛选条件 解决方案: 逐步添加约束:
Tool: SN-Query-Table
Parameters:
table_name: incident
query: active=true^priority=1^sys_created_on>=javascript:gs.daysAgo(30)
fields: sys_id
limit: 1
日期查询筛选不正确
现象: 基于日期的筛选条件包含了意外记录 原因:
- 日期字段与日期时间比较,或日期时间字段与日期比较
- 时区差异
- 比较时缺少时间部分 解决方案: 使用 ServiceNow 日期函数以确保可靠性:
// Use gs.daysAgo() instead of hardcoded dates
query: sys_created_on>=javascript:gs.daysAgo(30)
// For specific date ranges, include full datetime
query: sys_created_on>=2025-01-01 00:00:00^sys_created_on<2025-02-01 00:00:00
GlideAggregate 返回的计数异常
现象: 聚合计数与手动计数不一致 原因:
- ACL 限制从聚合结果中筛掉了记录
- 缺少 addQuery 条件
- 按错误的字段分组 解决方案: 与简单计数进行比较:
// Verify with GlideRecord count
var gr = new GlideRecord('incident');
gr.addEncodedQuery('active=true^priority=1');
gr.query();
gs.info('GlideRecord count: ' + gr.getRowCount());
点遍历查询性能
现象: 使用点遍历的查询速度很慢 原因: 多层点遍历会产生开销较大的 JOIN 解决方案: 限制点遍历深度,并优先添加有索引的条件:
// BAD: Deep dot-walk as primary filter
query: caller_id.department.company.name=Acme
// GOOD: Add indexed conditions first, limit dot-walk depth
query: active=true^priority IN 1,2^caller_id.department.name=IT
示例
示例 1:构建复杂的事件查询
Natural Language: "Show me all P1 and P2 incidents from the last 30 days
that are still open, assigned to either the Network or Server team,
and have not been updated in the last 48 hours"
Encoded Query:
active=true^priority IN 1,2^sys_created_on>=javascript:gs.daysAgo(30)^assignment_group.nameLIKENetwork^ORassignment_group.nameLIKEServer^sys_updated_on<javascript:gs.daysAgo(2)
Test:
Tool: SN-Query-Table
Parameters:
table_name: incident
query: active=true^priority IN 1,2^sys_created_on>=javascript:gs.daysAgo(30)^sys_updated_on<javascript:gs.daysAgo(2)
fields: sys_id,number,priority,assignment_group,sys_updated_on
limit: 20
示例 2:生成聚合报告脚本
Natural Language: "Create a summary showing the number of incidents
created each month this year, broken down by category"
GlideAggregate Script:
var ga = new GlideAggregate('incident');
ga.addQuery('sys_created_on', '>=', gs.beginningOfThisYear());
ga.addAggregate('COUNT');
ga.groupBy('category');
ga.addTrend('sys_created_on', 'month');
ga.query();
while (ga.next()) {
gs.info('Month: {0} | Category: {1} | Count: {2}',
ga.getValue('timeref'),
ga.getDisplayValue('category'),
ga.getAggregate('COUNT'));
}
示例 3:根据自然语言创建报告
Natural Language: "I need a pie chart showing the distribution
of change requests by risk level for the current quarter"
Tool: SN-Create-Record
Parameters:
table_name: sys_report
data:
title: "Change Requests by Risk Level (Current Quarter)"
table: "change_request"
type: "pie"
field: "risk"
filter: "sys_created_on>=javascript:gs.beginningOfThisQuarter()"
aggregate: "COUNT"
is_published: true
active: true
相关技能
reporting/analytics-generation- 使用 PA 指标构建完整的仪表板development/code-assist- 生成包含查询逻辑的完整脚本itsm/incident-lifecycle- 事件数据模型和字段参考admin/schema-discovery- 将查询应用于列表视图和筛选器