yeg
5 天以前 691f882740b46c5354fb33404fef6efb370e05dc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
<?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="com.battery.business.mapper.TDeviceIngestRecordMapper">
    <resultMap id="TDeviceIngestRecordResultMap" type="com.battery.business.domain.TDeviceIngestRecord">
        <id property="ingestId" column="ingest_id"/>
        <result property="adapterCode" column="adapter_code"/>
        <result property="payloadKind" column="payload_kind"/>
        <result property="devtype" column="devtype"/>
        <result property="devid" column="devid"/>
        <result property="subdevid" column="subdevid"/>
        <result property="chlid" column="chlid"/>
        <result property="vendorChannelNo" column="vendor_channel_no"/>
        <result property="recordSequence" column="record_sequence"/>
        <result property="recordKey" column="record_key"/>
        <result property="sourceRef" column="source_ref"/>
        <result property="deviceTimeUtc" column="device_time_utc"/>
        <result property="deviceTimeRaw" column="device_time_raw"/>
        <result property="timezoneId" column="timezone_id"/>
        <result property="cycleNo" column="cycle_no"/>
        <result property="stepNo" column="step_no"/>
        <result property="relativeTimeSeconds" column="relative_time_seconds"/>
        <result property="voltageV" column="voltage_v"/>
        <result property="currentA" column="current_a"/>
        <result property="chargeCapacityAh" column="charge_capacity_ah"/>
        <result property="dischargeCapacityAh" column="discharge_capacity_ah"/>
        <result property="chargeEnergyWh" column="charge_energy_wh"/>
        <result property="dischargeEnergyWh" column="discharge_energy_wh"/>
        <result property="payloadJson" column="payload_json"/>
        <result property="contentSha256" column="content_sha256"/>
        <result property="receivedAtUtc" column="received_at_utc"/>
    </resultMap>
 
    <!-- 落地行的显式列名,顺序与建表脚本一致;列集合不随运行期表结构变化。 -->
    <sql id="ingestColumns">ingest_id, adapter_code, payload_kind, devtype, devid, subdevid, chlid, vendor_channel_no,
        record_sequence, record_key,
        source_ref, device_time_utc, device_time_raw, timezone_id, cycle_no, step_no, relative_time_seconds,
        voltage_v, current_a, charge_capacity_ah, discharge_capacity_ah, charge_energy_wh, discharge_energy_wh,
        payload_json, content_sha256, received_at_utc</sql>
 
    <!-- 驼峰映射未开启(见 mybatis-config.xml),列名带下划线的查询一律显式映射。 -->
    <resultMap id="TDeviceIngestChannelResultMap" type="com.battery.business.domain.vo.TDeviceIngestChannel">
        <result property="devtype" column="devtype"/>
        <result property="devid" column="devid"/>
        <result property="subdevid" column="subdevid"/>
        <result property="chlid" column="chlid"/>
        <result property="vendorChannelNo" column="vendor_channel_no"/>
        <result property="lastDataAt" column="last_data_at"/>
    </resultMap>
 
    <!-- 落地行只追加:来源行身份(adapter_code + 类别 + record_key)撞键即视为重复推送,不改动既有事实。 -->
    <insert id="insertIngestRecord" parameterType="com.battery.business.domain.TDeviceIngestRecord"
            useGeneratedKeys="true" keyProperty="ingestId">
        insert ignore into t_device_ingest_record
        (adapter_code, payload_kind, devtype, devid, subdevid, chlid, vendor_channel_no, record_sequence, record_key,
         source_ref,
         device_time_utc, device_time_raw, timezone_id, cycle_no, step_no, relative_time_seconds,
         voltage_v, current_a, charge_capacity_ah, discharge_capacity_ah, charge_energy_wh, discharge_energy_wh,
         payload_json, content_sha256, received_at_utc)
        values (#{adapterCode}, #{payloadKind}, #{devtype}, #{devid}, #{subdevid}, #{chlid}, #{vendorChannelNo},
         #{recordSequence},
         #{recordKey}, #{sourceRef}, #{deviceTimeUtc}, #{deviceTimeRaw}, #{timezoneId}, #{cycleNo}, #{stepNo},
         #{relativeTimeSeconds}, #{voltageV}, #{currentA}, #{chargeCapacityAh}, #{dischargeCapacityAh},
         #{chargeEnergyWh}, #{dischargeEnergyWh}, cast(#{payloadJson} as json), #{contentSha256}, #{receivedAtUtc})
    </insert>
 
    <!-- 心跳单独占一行并覆盖接收时间:它只表示"取数程序还在推",不是设备事实,没有保留历史的意义。 -->
    <insert id="upsertHeartbeat" parameterType="com.battery.business.domain.TDeviceIngestRecord">
        insert into t_device_ingest_record
        (adapter_code, payload_kind, devtype, devid, subdevid, chlid, vendor_channel_no, record_sequence, record_key,
         source_ref,
         device_time_utc, device_time_raw, timezone_id, cycle_no, step_no, relative_time_seconds,
         voltage_v, current_a, charge_capacity_ah, discharge_capacity_ah, charge_energy_wh, discharge_energy_wh,
         payload_json, content_sha256, received_at_utc)
        values (#{adapterCode}, #{payloadKind}, #{devtype}, #{devid}, #{subdevid}, #{chlid}, #{vendorChannelNo},
         #{recordSequence},
         #{recordKey}, #{sourceRef}, #{deviceTimeUtc}, #{deviceTimeRaw}, #{timezoneId}, #{cycleNo}, #{stepNo},
         #{relativeTimeSeconds}, #{voltageV}, #{currentA}, #{chargeCapacityAh}, #{dischargeCapacityAh},
         #{chargeEnergyWh}, #{dischargeEnergyWh}, cast(#{payloadJson} as json), #{contentSha256}, #{receivedAtUtc})
        on duplicate key update received_at_utc = values(received_at_utc)
    </insert>
 
    <!-- 拓扑行是声明不是设备事实:重复上报刷新声明内容(例如来源补上它自己的通道号),不追加新行。 -->
    <insert id="upsertTopology" parameterType="com.battery.business.domain.TDeviceIngestRecord">
        insert into t_device_ingest_record
        (adapter_code, payload_kind, devtype, devid, subdevid, chlid, vendor_channel_no, record_sequence, record_key,
         source_ref,
         device_time_utc, device_time_raw, timezone_id, cycle_no, step_no, relative_time_seconds,
         voltage_v, current_a, charge_capacity_ah, discharge_capacity_ah, charge_energy_wh, discharge_energy_wh,
         payload_json, content_sha256, received_at_utc)
        values (#{adapterCode}, #{payloadKind}, #{devtype}, #{devid}, #{subdevid}, #{chlid}, #{vendorChannelNo},
         #{recordSequence},
         #{recordKey}, #{sourceRef}, #{deviceTimeUtc}, #{deviceTimeRaw}, #{timezoneId}, #{cycleNo}, #{stepNo},
         #{relativeTimeSeconds}, #{voltageV}, #{currentA}, #{chargeCapacityAh}, #{dischargeCapacityAh},
         #{chargeEnergyWh}, #{dischargeEnergyWh}, cast(#{payloadJson} as json), #{contentSha256}, #{receivedAtUtc})
        on duplicate key update vendor_channel_no = values(vendor_channel_no),
         payload_json = values(payload_json), content_sha256 = values(content_sha256),
         received_at_utc = values(received_at_utc)
    </insert>
 
    <select id="selectIngestRecordHashByKey" resultType="string">
        select lower(hex(content_sha256)) from t_device_ingest_record
        where adapter_code = #{adapterCode} and payload_kind = #{payloadKind} and record_key = #{recordKey}
        limit 1
    </select>
 
    <select id="selectHeartbeatAt" resultType="java.util.Date">
        select max(received_at_utc) from t_device_ingest_record
        where adapter_code = #{adapterCode} and payload_kind = 'HEARTBEAT'
    </select>
 
    <!-- 最近数据时间取该通道自己的采样行:没有新采样行就是没有,不按拓扑上报时间代替。 -->
    <select id="selectTopologyChannels" resultMap="TDeviceIngestChannelResultMap">
        select t.devtype, t.devid, t.subdevid, t.chlid, t.vendor_channel_no,
        (select max(prior.device_time_utc) from t_device_ingest_record prior
         where prior.adapter_code = t.adapter_code and prior.payload_kind = 'SAMPLE'
           and prior.devtype = t.devtype and prior.devid = t.devid
           and prior.subdevid = t.subdevid and prior.chlid = t.chlid) as last_data_at
        from t_device_ingest_record t
        where t.adapter_code = #{adapterCode} and t.payload_kind = 'TOPOLOGY'
        order by t.devid, t.subdevid, t.chlid
    </select>
 
    <select id="selectLatestSample" resultMap="TDeviceIngestRecordResultMap">
        select <include refid="ingestColumns"/> from t_device_ingest_record
        where adapter_code = #{adapterCode} and payload_kind = 'SAMPLE'
          and devtype = #{devtype} and devid = #{devid} and subdevid = #{subdevid} and chlid = #{chlid}
        order by device_time_utc desc, record_sequence desc
        limit 1
    </select>
 
    <!-- 一个来源库(厂商侧一次测试)在该通道上的全部采样行,供分段推导工步与循环(ADR-0067)。 -->
    <select id="selectSamplesOfSource" resultMap="TDeviceIngestRecordResultMap">
        select <include refid="ingestColumns"/> from t_device_ingest_record
        where adapter_code = #{adapterCode} and payload_kind = 'SAMPLE'
          and devtype = #{devtype} and devid = #{devid} and subdevid = #{subdevid} and chlid = #{chlid}
          and source_ref = #{sourceRef}
        order by device_time_utc, record_sequence
    </select>
 
    <!-- 只取严格晚于水位的行;同秒多行按协议序号各自成立,不按秒合并。 -->
    <select id="selectSamplesSince" resultMap="TDeviceIngestRecordResultMap">
        select <include refid="ingestColumns"/> from t_device_ingest_record
        where adapter_code = #{adapterCode} and payload_kind = 'SAMPLE'
          and devtype = #{devtype} and devid = #{devid} and subdevid = #{subdevid} and chlid = #{chlid}
        <if test="watermarkTime != null">
          and (device_time_utc &gt; #{watermarkTime}
               or (device_time_utc = #{watermarkTime} and record_sequence &gt; #{watermarkSequence}))
        </if>
        order by device_time_utc, record_sequence
        limit #{limit}
    </select>
</mapper>