/* 振动传感器振动温度整点报表 说明: 1. 存储过程 dbo.sp_InsertVibrationSensorHourlyReport 在整点执行时,默认取「上一完整小时」区间内, 每个 sensor_id 在 T_VibrationSensor_Data 中 collectTime 最晚的一条(并列时取 objId 较大者)。 2. reportTime 存该小时起始时间。例如 2025-03-23 09:00:00 表示统计区间 [09:00, 10:00) 的末条数据。 3. 定时请使用 SQL Server 代理作业(见脚本末尾示例),不要在应用内写 Quartz 定时任务。 该存储过程无入参: - 以「当前服务器时间的整点」为区间右端点(不包含),汇总上一小时。 - 区间为 [DATEADD(hour,-1,@EndExclusive), @EndExclusive)。 */ IF OBJECT_ID(N'dbo.T_VibrationSensor_Hourly_Report', N'U') IS NULL BEGIN CREATE TABLE dbo.T_VibrationSensor_Hourly_Report ( objId BIGINT IDENTITY CONSTRAINT PK_T_VibrationSensor_Hourly_Report PRIMARY KEY, reportTime DATETIME NOT NULL, sensor_id NVARCHAR(64) NOT NULL, collectTime DATETIME NULL, speed DECIMAL(18, 2) NULL, displacement DECIMAL(18, 2) NULL, acceleration DECIMAL(18, 2) NULL, temperature DECIMAL(18, 2) NULL, recodeTime DATETIME NOT NULL CONSTRAINT DF_T_VibrationSensor_Hourly_Report_recodeTime DEFAULT GETDATE(), remark VARCHAR(64) NULL, CONSTRAINT UQ_T_VibrationSensor_Hourly_Report_hour_sensor UNIQUE (reportTime, sensor_id) ); CREATE NONCLUSTERED INDEX IX_T_VibrationSensor_Hourly_Report_reportTime ON dbo.T_VibrationSensor_Hourly_Report (reportTime DESC); EXEC sp_addextendedproperty N'MS_Description', N'振动传感器整点报表(每小时末条采集)', N'SCHEMA', N'dbo', N'TABLE', N'T_VibrationSensor_Hourly_Report'; EXEC sp_addextendedproperty N'MS_Description', N'主键', N'SCHEMA', N'dbo', N'TABLE', N'T_VibrationSensor_Hourly_Report', N'COLUMN', N'objId'; EXEC sp_addextendedproperty N'MS_Description', N'报表归属小时(该小时起点)', N'SCHEMA', N'dbo', N'TABLE', N'T_VibrationSensor_Hourly_Report', N'COLUMN', N'reportTime'; EXEC sp_addextendedproperty N'MS_Description', N'振动传感器ID', N'SCHEMA', N'dbo', N'TABLE', N'T_VibrationSensor_Hourly_Report', N'COLUMN', N'sensor_id'; EXEC sp_addextendedproperty N'MS_Description', N'该小时内末条记录的采集时间', N'SCHEMA', N'dbo', N'TABLE', N'T_VibrationSensor_Hourly_Report', N'COLUMN', N'collectTime'; EXEC sp_addextendedproperty N'MS_Description', N'速度(mm/s)', N'SCHEMA', N'dbo', N'TABLE', N'T_VibrationSensor_Hourly_Report', N'COLUMN', N'speed'; EXEC sp_addextendedproperty N'MS_Description', N'位移(um)', N'SCHEMA', N'dbo', N'TABLE', N'T_VibrationSensor_Hourly_Report', N'COLUMN', N'displacement'; EXEC sp_addextendedproperty N'MS_Description', N'加速度(g)', N'SCHEMA', N'dbo', N'TABLE', N'T_VibrationSensor_Hourly_Report', N'COLUMN', N'acceleration'; EXEC sp_addextendedproperty N'MS_Description', N'温度(℃)', N'SCHEMA', N'dbo', N'TABLE', N'T_VibrationSensor_Hourly_Report', N'COLUMN', N'temperature'; EXEC sp_addextendedproperty N'MS_Description', N'写入报表时间', N'SCHEMA', N'dbo', N'TABLE', N'T_VibrationSensor_Hourly_Report', N'COLUMN', N'recodeTime'; EXEC sp_addextendedproperty N'MS_Description', N'备注', N'SCHEMA', N'dbo', N'TABLE', N'T_VibrationSensor_Hourly_Report', N'COLUMN', N'remark'; END GO IF OBJECT_ID(N'dbo.sp_InsertVibrationSensorHourlyReport', N'P') IS NOT NULL DROP PROCEDURE dbo.sp_InsertVibrationSensorHourlyReport; GO CREATE PROCEDURE dbo.sp_InsertVibrationSensorHourlyReport AS BEGIN SET NOCOUNT ON; SET XACT_ABORT ON; DECLARE @EndExclusive DATETIME = DATEADD(HOUR, DATEDIFF(HOUR, 0, GETDATE()), 0); DECLARE @StartInclusive DATETIME = DATEADD(HOUR, -1, @EndExclusive); DECLARE @ReportTime DATETIME = @StartInclusive; ;WITH Ranked AS ( SELECT d.objId, d.sensor_id, d.collectTime, d.speed, d.displacement, d.acceleration, d.temperature, d.remark, ROW_NUMBER() OVER ( PARTITION BY d.sensor_id ORDER BY d.collectTime DESC, d.objId DESC ) AS rn FROM dbo.T_VibrationSensor_Data d WHERE d.collectTime >= @StartInclusive AND d.collectTime < @EndExclusive ) INSERT INTO dbo.T_VibrationSensor_Hourly_Report (reportTime, sensor_id, collectTime, speed, displacement, acceleration, temperature, recodeTime, remark) SELECT @ReportTime, r.sensor_id, @ReportTime, r.speed, r.displacement, r.acceleration, r.temperature, @ReportTime, r.remark FROM Ranked r WHERE r.rn = 1 AND NOT EXISTS ( SELECT 1 FROM dbo.T_VibrationSensor_Hourly_Report x WHERE x.reportTime = @ReportTime AND x.sensor_id = r.sensor_id ); -- 清理原始明细:删除 recodeTime 三个月前的数据 DELETE FROM dbo.T_VibrationSensor_Data WHERE recodeTime < DATEADD(MONTH, -3, @EndExclusive); END GO IF NOT EXISTS ( SELECT 1 FROM sys.extended_properties ep WHERE ep.class = 1 AND ep.major_id = OBJECT_ID(N'dbo.sp_InsertVibrationSensorHourlyReport') AND ep.minor_id = 0 AND ep.name = N'MS_Description' ) EXEC sp_addextendedproperty N'MS_Description', N'按小时汇总振动温度:无入参,固定按当前整点回算上一小时,取各传感器 collectTime 最后一条写入整点报表。', N'SCHEMA', N'dbo', N'PROCEDURE', N'sp_InsertVibrationSensorHourlyReport'; ELSE EXEC sp_updateextendedproperty N'MS_Description', N'按小时汇总振动温度:无入参,固定按当前整点回算上一小时,取各传感器 collectTime 最后一条写入整点报表。', N'SCHEMA', N'dbo', N'PROCEDURE', N'sp_InsertVibrationSensorHourlyReport'; GO /* -------------------------------------------------------------------- 若依菜单与权限(在「菜单管理」中自行添加,或执行类似语句,注意 menu_id / parent_id 勿冲突) -- 目录或菜单 C:url = /system/TVibrationSensorHourlyReport -- perms: system:TVibrationSensorHourlyReport:view / list / export INSERT INTO sys_menu (menu_name, parent_id, order_num, url, menu_type, visible, perms, icon, create_by, create_time, remark) VALUES (N'振动整点报表', <父菜单ID>, 10, N'/system/TVibrationSensorHourlyReport', N'C', N'0', N'system:TVibrationSensorHourlyReport:view', N'fa fa-table', N'admin', GETDATE(), N''); -- 将返回的 menu_id 记入 @mid,再插入按钮权限 F: -- system:TVibrationSensorHourlyReport:list -- system:TVibrationSensorHourlyReport:export -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- SQL Server 代理作业(在 SSMS 中图形化创建,或按需执行以下模板并修改作业名) USE msdb; GO EXEC dbo.sp_add_job @job_name = N'振动传感器整点报表', @enabled = 1, @description = N'每小时执行 sp_InsertVibrationSensorHourlyReport'; GO EXEC dbo.sp_add_jobstep @job_name = N'振动传感器整点报表', @step_name = N'写入整点报表', @subsystem = N'TSQL', @database_name = N'你的数据库名', @command = N'EXEC dbo.sp_InsertVibrationSensorHourlyReport;', @retry_attempts = 2, @retry_interval = 5; GO EXEC dbo.sp_add_schedule @schedule_name = N'每小时整点', @freq_type = 4, @freq_interval = 1, @freq_subday_type = 8, @freq_subday_interval = 1, @active_start_time = 0; GO EXEC dbo.sp_attach_schedule @job_name = N'振动传感器整点报表', @schedule_name = N'每小时整点'; GO EXEC dbo.sp_add_jobserver @job_name = N'振动传感器整点报表'; GO 注意:@active_start_time = 0 表示从 00:00:00 起每 1 小时一次(与 freq_subday 组合为每小时)。 若环境与版本不同,请用 SSMS「新建作业」→「步骤」执行上述 EXEC →「计划」选「重复执行」每小时、在整点触发更直观。 -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- 振动整点报表随机测试数据(可直接执行) 说明: 1) 生成“今天 00:00 ~ 当前小时前一小时”之间,2 个传感器、每小时 1 条随机整点报表数据。 2) 已存在同小时同传感器数据会跳过(依赖唯一键 reportTime + sensor_id)。 -------------------------------------------------------------------- */ DECLARE @TodayStart DATETIME = DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0); DECLARE @CurrentHour DATETIME = DATEADD(HOUR, DATEDIFF(HOUR, 0, GETDATE()), 0); ;WITH H AS ( SELECT @TodayStart AS reportTime UNION ALL SELECT DATEADD(HOUR, 1, reportTime) FROM H WHERE DATEADD(HOUR, 1, reportTime) < @CurrentHour ), S AS ( SELECT N'VS-001' AS sensor_id UNION ALL SELECT N'VS-002' ), R AS ( SELECT h.reportTime, s.sensor_id, h.reportTime AS collectTime, CAST((ABS(CHECKSUM(NEWID())) % 1200) / 100.0 AS DECIMAL(18, 2)) AS speed, CAST((ABS(CHECKSUM(NEWID())) % 5000) / 100.0 AS DECIMAL(18, 2)) AS displacement, CAST((ABS(CHECKSUM(NEWID())) % 300) / 100.0 AS DECIMAL(18, 2)) AS acceleration, CAST((ABS(CHECKSUM(NEWID())) % 7000) / 100.0 AS DECIMAL(18, 2)) AS temperature FROM H h CROSS JOIN S s ) INSERT INTO dbo.T_VibrationSensor_Hourly_Report ( reportTime, sensor_id, collectTime, speed, displacement, acceleration, temperature, recodeTime, remark ) SELECT r.reportTime, r.sensor_id, r.collectTime, r.speed, r.displacement, r.acceleration, r.temperature, r.reportTime, N'随机测试数据' FROM R r WHERE NOT EXISTS ( SELECT 1 FROM dbo.T_VibrationSensor_Hourly_Report x WHERE x.reportTime = r.reportTime AND x.sensor_id = r.sensor_id ) OPTION (MAXRECURSION 1000); GO