|
|
|
|
@ -0,0 +1,246 @@
|
|
|
|
|
<?xml version="1.0" encoding="UTF-8" ?>
|
|
|
|
|
<!DOCTYPE mapper
|
|
|
|
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|
|
|
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
|
|
|
|
<mapper namespace="org.dromara.ems.report.mapper.DisplacementBoardMapper">
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
位移专属看板 XML,与振动通用 XML 解耦。
|
|
|
|
|
所有分析类 SQL 在 WHERE 中固定过滤 vibration_displacement IS NOT NULL AND > 0,
|
|
|
|
|
避免先查四维指标再在 Java 层裁剪成位移数据,减少数据库 I/O 与内存压力。
|
|
|
|
|
|
|
|
|
|
保留 RecordIotenvInstant 作为结果映射,是因为位移看板在聚合层仍要读取
|
|
|
|
|
monitor_id / monitor_name / recode_time / vibration_displacement 等字段,
|
|
|
|
|
建新实体反而需要同步维护多个一致性,收益不大。
|
|
|
|
|
-->
|
|
|
|
|
<resultMap type="org.dromara.ems.record.domain.RecordIotenvInstant" id="DisplacementBoardResult">
|
|
|
|
|
<result property="objid" column="objid"/>
|
|
|
|
|
<result property="monitorId" column="monitorId"/>
|
|
|
|
|
<result property="monitorCode" column="monitor_code"/>
|
|
|
|
|
<result property="monitorName" column="monitor_name"/>
|
|
|
|
|
<result property="vibrationDisplacement" column="vibration_displacement"/>
|
|
|
|
|
<result property="collectTime" column="collectTime"/>
|
|
|
|
|
<result property="recodeTime" column="recodeTime"/>
|
|
|
|
|
</resultMap>
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
位移看板只需要位移相关字段,避免把四维振动字段一并 SELECT 浪费 IO;
|
|
|
|
|
monitor_name 通过 INNER JOIN ems_base_monitor_info 获取,
|
|
|
|
|
COALESCE 兜底避免主数据未维护导致前端报错。
|
|
|
|
|
-->
|
|
|
|
|
<sql id="selectColumns">
|
|
|
|
|
t.objid,
|
|
|
|
|
t.monitorId,
|
|
|
|
|
t.vibration_displacement,
|
|
|
|
|
t.collectTime,
|
|
|
|
|
t.recodeTime,
|
|
|
|
|
COALESCE(ebmi.monitor_name, t.monitorId) AS monitor_name,
|
|
|
|
|
t.monitorId AS monitor_code
|
|
|
|
|
</sql>
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
分析类 WHERE:
|
|
|
|
|
1. 时间范围(参数化绑定 #{} 防注入)
|
|
|
|
|
2. 设备过滤(支持单设备 / 多设备 IN 列表)
|
|
|
|
|
3. vibration_displacement 有效值过滤——位移看板分析类 SQL 的专属口径
|
|
|
|
|
注意:不做上限截断,高位位移本身就是业务风险信号。
|
|
|
|
|
-->
|
|
|
|
|
<sql id="baseWhere">
|
|
|
|
|
t.recodeTime >= #{query.beginRecordTime}
|
|
|
|
|
AND t.recodeTime <= #{query.endRecordTime}
|
|
|
|
|
<choose>
|
|
|
|
|
<when test="query.monitorId != null and query.monitorId != ''">
|
|
|
|
|
AND t.monitorId = #{query.monitorId}
|
|
|
|
|
</when>
|
|
|
|
|
<when test="query.monitorIds != null and query.monitorIds.size() > 0">
|
|
|
|
|
AND t.monitorId IN
|
|
|
|
|
<foreach collection="query.monitorIds" item="monitorId" open="(" separator="," close=")">
|
|
|
|
|
#{monitorId}
|
|
|
|
|
</foreach>
|
|
|
|
|
</when>
|
|
|
|
|
</choose>
|
|
|
|
|
AND t.vibration_displacement IS NOT NULL
|
|
|
|
|
AND t.vibration_displacement > 0
|
|
|
|
|
</sql>
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
质量页 WHERE:仅按时间/设备过滤,不做位移有效值过滤,
|
|
|
|
|
避免质量页分母被提前缩小导致覆盖率虚高。
|
|
|
|
|
-->
|
|
|
|
|
<sql id="baseWhereQuality">
|
|
|
|
|
t.recodeTime >= #{query.beginRecordTime}
|
|
|
|
|
AND t.recodeTime <= #{query.endRecordTime}
|
|
|
|
|
<choose>
|
|
|
|
|
<when test="query.monitorId != null and query.monitorId != ''">
|
|
|
|
|
AND t.monitorId = #{query.monitorId}
|
|
|
|
|
</when>
|
|
|
|
|
<when test="query.monitorIds != null and query.monitorIds.size() > 0">
|
|
|
|
|
AND t.monitorId IN
|
|
|
|
|
<foreach collection="query.monitorIds" item="monitorId" open="(" separator="," close=")">
|
|
|
|
|
#{monitorId}
|
|
|
|
|
</foreach>
|
|
|
|
|
</when>
|
|
|
|
|
</choose>
|
|
|
|
|
</sql>
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
原始查询:UNION ALL 多日分表 → 子查询 → 排序。
|
|
|
|
|
INNER JOIN monitor_type = 10 确保只查振动类设备(现场物理意义:振动位移传感器挂在 type=10 下)。
|
|
|
|
|
${tableName} 虽然是拼接而非参数化,但 Service 已做白名单正则校验(TABLE_NAME_PATTERN),
|
|
|
|
|
此处是唯一允许 ${} 的位置。
|
|
|
|
|
-->
|
|
|
|
|
<sql id="rawPageQuery">
|
|
|
|
|
SELECT *
|
|
|
|
|
FROM (
|
|
|
|
|
<foreach collection="tableNames" item="tableName" separator=" UNION ALL ">
|
|
|
|
|
SELECT
|
|
|
|
|
<include refid="selectColumns"/>
|
|
|
|
|
FROM ${tableName} t
|
|
|
|
|
INNER JOIN ems_base_monitor_info ebmi
|
|
|
|
|
ON t.monitorId = ebmi.monitor_code
|
|
|
|
|
AND ebmi.monitor_type = 10
|
|
|
|
|
<where>
|
|
|
|
|
<include refid="baseWhere"/>
|
|
|
|
|
</where>
|
|
|
|
|
</foreach>
|
|
|
|
|
) displacement_data
|
|
|
|
|
<!-- 排序:先设备、再时间、最后主键,保证 Java 层“取最新值”“相邻点差值”算法稳定 -->
|
|
|
|
|
ORDER BY displacement_data.monitorId ASC, displacement_data.recodeTime ASC, displacement_data.objid ASC
|
|
|
|
|
</sql>
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
抽样查询:使用 ROW_NUMBER 窗口函数按「设备 + 时间桶」分区,每个桶只保留最新一条记录。
|
|
|
|
|
时间桶宽度 = samplingInterval 分钟,通过 DATEDIFF/TIMESTAMPDIFF 计算桶编号。
|
|
|
|
|
多数据库兼容:通过 _databaseId 判断 MySQL/PostgreSQL/SQL Server 语法差异。
|
|
|
|
|
-->
|
|
|
|
|
<sql id="samplingPageQuery">
|
|
|
|
|
WITH sampled AS (
|
|
|
|
|
<foreach collection="tableNames" item="tableName" separator=" UNION ALL ">
|
|
|
|
|
SELECT
|
|
|
|
|
<include refid="selectColumns"/>,
|
|
|
|
|
ROW_NUMBER() OVER (
|
|
|
|
|
PARTITION BY t.monitorId,
|
|
|
|
|
<choose>
|
|
|
|
|
<when test="_databaseId == 'mysql'">
|
|
|
|
|
CAST(TIMESTAMPDIFF(MINUTE, '2000-01-01 00:00:00', t.recodeTime) / #{query.samplingInterval} AS SIGNED)
|
|
|
|
|
</when>
|
|
|
|
|
<when test="_databaseId == 'postgresql' or _databaseId == 'PostgreSQL'">
|
|
|
|
|
CAST(EXTRACT(EPOCH FROM (t.recodeTime - TIMESTAMP '2000-01-01 00:00:00')) / 60 / #{query.samplingInterval} AS BIGINT)
|
|
|
|
|
</when>
|
|
|
|
|
<otherwise>
|
|
|
|
|
CAST(DATEDIFF(MINUTE, '2000-01-01 00:00:00', t.recodeTime) / #{query.samplingInterval} AS BIGINT)
|
|
|
|
|
</otherwise>
|
|
|
|
|
</choose>
|
|
|
|
|
ORDER BY t.recodeTime DESC, t.objid DESC
|
|
|
|
|
) AS rn
|
|
|
|
|
FROM ${tableName} t
|
|
|
|
|
INNER JOIN ems_base_monitor_info ebmi
|
|
|
|
|
ON t.monitorId = ebmi.monitor_code
|
|
|
|
|
AND ebmi.monitor_type = 10
|
|
|
|
|
<where>
|
|
|
|
|
<include refid="baseWhere"/>
|
|
|
|
|
</where>
|
|
|
|
|
</foreach>
|
|
|
|
|
)
|
|
|
|
|
SELECT
|
|
|
|
|
objid,
|
|
|
|
|
monitorId,
|
|
|
|
|
monitor_code,
|
|
|
|
|
monitor_name,
|
|
|
|
|
vibration_displacement,
|
|
|
|
|
collectTime,
|
|
|
|
|
recodeTime
|
|
|
|
|
FROM sampled
|
|
|
|
|
<!-- rn = 1 为每个“设备+时间桶”内最新的一条,效果等价于“每 N 分钟取一个位移采样点” -->
|
|
|
|
|
WHERE rn = 1
|
|
|
|
|
ORDER BY monitorId ASC, recodeTime ASC, objid ASC
|
|
|
|
|
</sql>
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
质量页原始查询:不按位移有效值过滤,
|
|
|
|
|
保证分母代表“本次查询实际采到的样本总数”。
|
|
|
|
|
-->
|
|
|
|
|
<sql id="rawQualityQuery">
|
|
|
|
|
SELECT *
|
|
|
|
|
FROM (
|
|
|
|
|
<foreach collection="tableNames" item="tableName" separator=" UNION ALL ">
|
|
|
|
|
SELECT
|
|
|
|
|
<include refid="selectColumns"/>
|
|
|
|
|
FROM ${tableName} t
|
|
|
|
|
INNER JOIN ems_base_monitor_info ebmi
|
|
|
|
|
ON t.monitorId = ebmi.monitor_code
|
|
|
|
|
AND ebmi.monitor_type = 10
|
|
|
|
|
<where>
|
|
|
|
|
<include refid="baseWhereQuality"/>
|
|
|
|
|
</where>
|
|
|
|
|
</foreach>
|
|
|
|
|
) displacement_quality_data
|
|
|
|
|
ORDER BY displacement_quality_data.monitorId ASC, displacement_quality_data.recodeTime ASC, displacement_quality_data.objid ASC
|
|
|
|
|
</sql>
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
质量页抽样查询:仅做时间桶抽样,不做位移有效值过滤,
|
|
|
|
|
避免质量统计在 SQL 层被“分析口径”提前污染。
|
|
|
|
|
-->
|
|
|
|
|
<sql id="samplingQualityQuery">
|
|
|
|
|
WITH sampled AS (
|
|
|
|
|
<foreach collection="tableNames" item="tableName" separator=" UNION ALL ">
|
|
|
|
|
SELECT
|
|
|
|
|
<include refid="selectColumns"/>,
|
|
|
|
|
ROW_NUMBER() OVER (
|
|
|
|
|
PARTITION BY t.monitorId,
|
|
|
|
|
<choose>
|
|
|
|
|
<when test="_databaseId == 'mysql'">
|
|
|
|
|
CAST(TIMESTAMPDIFF(MINUTE, '2000-01-01 00:00:00', t.recodeTime) / #{query.samplingInterval} AS SIGNED)
|
|
|
|
|
</when>
|
|
|
|
|
<when test="_databaseId == 'postgresql' or _databaseId == 'PostgreSQL'">
|
|
|
|
|
CAST(EXTRACT(EPOCH FROM (t.recodeTime - TIMESTAMP '2000-01-01 00:00:00')) / 60 / #{query.samplingInterval} AS BIGINT)
|
|
|
|
|
</when>
|
|
|
|
|
<otherwise>
|
|
|
|
|
CAST(DATEDIFF(MINUTE, '2000-01-01 00:00:00', t.recodeTime) / #{query.samplingInterval} AS BIGINT)
|
|
|
|
|
</otherwise>
|
|
|
|
|
</choose>
|
|
|
|
|
ORDER BY t.recodeTime DESC, t.objid DESC
|
|
|
|
|
) AS rn
|
|
|
|
|
FROM ${tableName} t
|
|
|
|
|
INNER JOIN ems_base_monitor_info ebmi
|
|
|
|
|
ON t.monitorId = ebmi.monitor_code
|
|
|
|
|
AND ebmi.monitor_type = 10
|
|
|
|
|
<where>
|
|
|
|
|
<include refid="baseWhereQuality"/>
|
|
|
|
|
</where>
|
|
|
|
|
</foreach>
|
|
|
|
|
)
|
|
|
|
|
SELECT
|
|
|
|
|
objid,
|
|
|
|
|
monitorId,
|
|
|
|
|
monitor_code,
|
|
|
|
|
monitor_name,
|
|
|
|
|
vibration_displacement,
|
|
|
|
|
collectTime,
|
|
|
|
|
recodeTime
|
|
|
|
|
FROM sampled
|
|
|
|
|
WHERE rn = 1
|
|
|
|
|
ORDER BY monitorId ASC, recodeTime ASC, objid ASC
|
|
|
|
|
</sql>
|
|
|
|
|
|
|
|
|
|
<!-- 分析类原始明细(samplingInterval <= 1 时使用) -->
|
|
|
|
|
<select id="selectRawData" resultMap="DisplacementBoardResult">
|
|
|
|
|
<include refid="rawPageQuery"/>
|
|
|
|
|
</select>
|
|
|
|
|
|
|
|
|
|
<!-- 分析类抽样明细(samplingInterval > 1 时使用,DB 层降采样) -->
|
|
|
|
|
<select id="selectSampledData" resultMap="DisplacementBoardResult">
|
|
|
|
|
<include refid="samplingPageQuery"/>
|
|
|
|
|
</select>
|
|
|
|
|
|
|
|
|
|
<!-- 质量页原始样本(samplingInterval <= 1 时使用) -->
|
|
|
|
|
<select id="selectQualityRawData" resultMap="DisplacementBoardResult">
|
|
|
|
|
<include refid="rawQualityQuery"/>
|
|
|
|
|
</select>
|
|
|
|
|
|
|
|
|
|
<!-- 质量页抽样样本(samplingInterval > 1 时使用) -->
|
|
|
|
|
<select id="selectQualitySampledData" resultMap="DisplacementBoardResult">
|
|
|
|
|
<include refid="samplingQualityQuery"/>
|
|
|
|
|
</select>
|
|
|
|
|
</mapper>
|