EMQX6.2企业版 接入mssqlserver 2022 update语句报无法匹配sql模版错误

环境:ROCKY 8.1 EMQX6.2 企业版 SQLSERVER2022
数据库表建表语句:
CREATE TABLE [dbo].[DeviceStatus_Current](
[id] [int] IDENTITY(1,1) NOT NULL,
[create_time] datetime2 NOT NULL,
[type] [int] NULL,
[Device_No] varchar NULL,
[Status] [int] NULL,
[Fault] [int] NULL,
[Fault_Type] [int] NULL,
CONSTRAINT [PK_DeviceStatus_Current] PRIMARY KEY CLUSTERED
(
[create_time] ASC,
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF, DATA_COMPRESSION = PAGE) ON ps_SCADA_monthly
) ON ps_SCADA_monthly
GO

动作sql
UPDATE DeviceStatus_Current SET Fault = ‘0’

运行测试时报错:
{
“time”: “2026-06-26T13:41:29.435780+08:00”,
“msg”: “action_failed”,
“meta”: {
“trace_tag”: “ACTION”,
“rule_trigger_ts”: [
1782452489372
],
“rule_id”: “rule_020101_DL01_Status”,
“reason”: “failed_to_apply_sql_template”,
“namespace”: “global”,
“clientid”: “020101_DL01”,
“action_info”: {
“type”: “sqlserver”,
“name”: “DL01_Status_Current”
}
},
“level”: “debug”
}

后台报错:
{“time”:1782452849429363,“level”:“error”,“msg”:“sqlserver_connector_do_query_failed”,“rule_trigger_ts”:[1782452849367],“rule_ids”:{“rule_020101_DL01_Status”:true},“client_ids”:{“020101_DL01”:true},“payload_encode”:“text”,“namespace”:“global”,“connector”:“connector:sqlserver:JR-SCADA-DB-01”,“query”:“Encoded(text)={<<"action:sqlserver:DL01_Status_Current:connector:sqlserver:JR-SCADA-DB-01">>,#{<<"DEVICE_Fault">> => <<>>,<<"DEVICE_Status">> => 2,<<"Fault_Type">> => <<>>,<<"time_ms">> => <<"1782452850">>,<<"type">> => 0}}”,“reason”:“{unrecoverable_error,failed_to_apply_sql_template}”,“pid”:“<0.468501.0>”,“line”:510}
{“time”:1782452849429841,“level”:“error”,“msg”:“unrecoverable_resource_error”,“resource_id”:“action:sqlserver:DL01_Status_Current:connector:sqlserver:JR-SCADA-DB-01”,“namespace”:“global”,“tag”:“RESOURCE”,“reason”:“{unrecoverable_error,failed_to_apply_sql_template}”,“pid”:“<0.468501.0>”}

执行insert into可以正常运行,update就报错。
请问如何排查?谢谢

这个错是 SQL 模板渲染,不是 SQL Server 已经执行 UPDATE 后报错。
failed_to_apply_sql_template 发生在 EMQX 把规则输出套进 Sink 的 SQL 模板时。日志里实际传给 action 的字段大概是这些:

DEVICE_Fault = ""
DEVICE_Status = 2
Fault_Type = ""
time_ms = "1782452850"
type = 0
  1. 打开规则的“启用调试”,确认 SELECT 输出字段名和 Sink SQL 模板里的 ${xxx} 完全一致,大小写也要一致。模板里如果写了 ${Fault} / ${Status},但规则输出是 DEVICE_Fault / DEVICE_Status,就会在模板应用时挂掉。

  2. SQL Server Sink 是预处理 SQL,占位符不要加引号,SQL 末尾不要加分号。先用最小模板测通:

UPDATE dbo.DeviceStatus_Current
SET Fault = 0
WHERE Device_No = ${clientid}

如果 Device_No 不是 clientid,就在规则 SQL 里把设备号字段 SELECT ... AS Device_No 出来,然后模板用 ${Device_No}

  1. 日志里 DEVICE_FaultFault_Type 是空字符串。它们要写进 int 字段的话,先在规则 SQL 里搞个默认的数字或 NULL,比如:
SELECT
  clientid,
  coalesce_ne(DEVICE_Fault, 0) as DEVICE_Fault,
  coalesce_ne(Fault_Type, 0) as Fault_Type,
  DEVICE_Status
FROM
  "你的主题"

然后模板再写:

UPDATE dbo.DeviceStatus_Current
SET Fault = ${DEVICE_Fault},
    Status = ${DEVICE_Status},
    Fault_Type = ${Fault_Type}
WHERE Device_No = ${clientid}

PS: 表结构里的 Device_No varchar 没写长度,SQL Server 里通常会按很短的长度处理。这个字段如果要存设备号,先确认实际表结构是不是 varchar(64) 这类明确长度。

如果改完还报,把规则 SQL 调试输出和Sink SQL 模板完整内容贴出来。现在的日志怀疑模板变量名对不上,或者空字符串写进了整数字段。

您好!
1、调试模式下,规则sql输出如下

{
“type”: 0,
“time_s”: “1782459030”,
“Status”: 2,
“Fault_Type”: 0,
“Fault”: 0,
“Device_No”: “DL01”
}

2、动作输出sql,使用给的最小模板如下:

UPDATE dbo.DeviceStatus_Current

SET Fault = 0

WHERE Device_No = ‘DL01’

高级设置:最大批量请求大小 1,请求模式:异步。其余默认。

调试模式反馈错误。
{
“time”: “2026-06-26T15:34:29.243703+08:00”,
“msg”: “async_query_received”,
“meta”: {
“trigger”: “",
“trace_tag”: “QUERY”,
“rule_trigger_ts”: [
1782459269241
],
“rule_id”: "rule_
_Status",
“peername”: "
",
“namespace”: “global”,
“matched”: "
",
“clientid”: "
******”,
“action_info”: {
“type”: “sqlserver”,
“name”: “DL01_Status_Current”
}
},
“level”: “debug”
}

sql依旧是动作执行失败
{
“time”: “2026-06-26T15:34:29.315291+08:00”,
“msg”: “action_failed”,
“meta”: {
“trace_tag”: “ACTION”,
“rule_trigger_ts”: [
1782459269241
],
“rule_id”: “rule_020101_DL01_Status”,
“reason”: “failed_to_apply_sql_template”,
“namespace”: “global”,
“clientid”: “020101_DL01”,
“action_info”: {
“type”: “sqlserver”,
“name”: “DL01_Status_Current”
}
},
“level”: “debug”
}

3、同一个规则下的另一个动作sql ,是insert into插入语句。该动作 的高级设置都是默认值。

INSERT INTO DeviceStatus (
create_time,
type,
Device_No,
Status,
Fault,
Fault_Type
)
VALUES (
DATEADD(HOUR, 8, DATEADD(SECOND, CAST(${time_s} AS BIGINT), ‘1970-01-01’)),
${type},
${Device_No} ,
${Status} ,
${Fault},
${Fault_Type}
)
可以执行成功。

规则输出
02
image

看起来连:

UPDATE dbo.DeviceStatus_Current SET Fault = 0 WHERE Device_No = 'DL01'

都有问题,这些都是硬编码的啊。和 EMQX 关系不大了。建议你直接用 mssql 的自己的 client 上执行一下这个语句看看到底报什么错。。。

你好!
我在上一条回复的最后给的就是用数据库客户端本地执行sql的结果,是可以执行的。

emqx报的错是 无法应用sql模板,即未能生成sql语句。始终未能找到不套用模板的原因的日志

这么一看应是 SQL Server Sink 这条动作没有把 UPDATE 当成可用的 SQL 模板解析。
现在这个现象已经能解释:

  • 同一条 UPDATE dbo.DeviceStatus_Current SET Fault = 0 WHERE Device_No = 'DL01' 在数据库客户端能执行
  • EMQX 里报的是 failed_to_apply_sql_template
  • 这个错误发生在 EMQX 套 SQL 模板阶段,还没走到 ODBC 执行 SQL Server
    INSERT 能成功,UPDATE 硬编码也失败,重点就在动作 SQL 模板类型。
    可以绕:EMQX SQL Server Sink 只写入一张中间表,用 INSERT
INSERT INTO dbo.DeviceStatus_Current_Inbox(Device_No, Fault, Status, Fault_Type, create_time)
VALUES (${Device_No}, ${Fault}, ${Status}, ${Fault_Type}, SYSDATETIME())

然后在 SQL Server 侧用 trigger/job/procedure 去更新当前状态表,例如:

CREATE TRIGGER dbo.trg_DeviceStatus_Current_Inbox
ON dbo.DeviceStatus_Current_Inbox
AFTER INSERT
AS
BEGIN
  SET NOCOUNT ON;
  UPDATE c
  SET c.Fault = i.Fault,
      c.Status = i.Status,
      c.Fault_Type = i.Fault_Type
  FROM dbo.DeviceStatus_Current c
  JOIN inserted i ON c.Device_No = i.Device_No;
END

如果你要继续走 EMQX 直接 UPDATE,建议带上这个最小复现步骤去GitHub 提 issue:SQL Server Sink 中 INSERT 模板可用,但硬编码 UPDATE 模板在执行前就 failed_to_apply_sql_template

这不像是这条 UPDATE SQL 写法问题。