[英]Dynamic SQL query from different Historian tables
我在 SQL 服务器中有一个历史系统,它将某些标签值保存在一个表中。
每个月,系统都会根据下表为这些历史数据创建一个表(分区表)。
例如,此表为 2021 年 2 月 ( [ sqlt_data_1_2021_02 ]
):
还有另一个表拥有分区表的名称以及每个历史表的开始和结束日期:
我需要根据开始/结束日期获取 [sqlt_data_x_x_x] 中历史值的数据。 例如: start Date: 10th of Dec 2020 EndDate: 10th of Feb2021
。
这意味着查询应该首先查看所需的分区表,在这种情况下。 是[ sqlt_data_1_2021_02], [ sqlt_data_1_2021_01], [ sqlt_data_1_2020_12]
。
然后查询将从这三个表中检索日期,并从UNION ALL
中检索结果。
我怎样才能动态地做到这一点,因为开始和结束日期是可变的?
我添加了有关要求的更多说明
--第一次查询
select id from sqlth_te where tagpath like '%tagName%' --tagname is Param for SP
--Result will be ID=153
第二次查询 end_time 和 Start_time 作为 SP 中的参数
SELECT pname from sqlth_partitions where end_time >=1611489115070 and sqlth_partitions.start_time <= 1612127027358
--result [sqlt_data_1_2021_01] ,[sqlt_data_1_2021_02]
第三个查询,使用上面查询的结果,它给出了表名
select floatvalue,t_stamp from sqlt_data_1_2021_01 where tagid='153' and t_stamp >=1611489115070--StartDate
union all
select floatvalue,t_stamp from sqlt_data_1_2021_02 where tagid='153'and t_stamp<=1612127027358--EndDate
Sp 所需参数应为 [ EXEC SPname 'tagname',end_time,Start_time
]
一种选择是创建一个获取所有表的动态查询。 但它可能容易出错且难以调试。
相反,我认为您最好的选择是使用动态 SQL 来创建一个视图,其中包含聚合在一起的所有必要表。 我们可以使用 SQL 服务器代理作业来定期维护视图,使用以下代码:
DECLARE @sql nvarchar(max) =
N'CREATE OR ALTER VIEW all_history AS
' +
(SELECT STRING_AGG(
N'SELECT ' +
QUOTENAME(p.name, '''') + N' AS name, ' +
p.start_time + N' AS start_time, ' +
p.end_time + N' AS end_time, * FROM ' +
QUOTENAME(p.name)
, CAST(N'
UNION ALL
' AS nvarchar(max))
FROM sqlth_partitions p
);
-- PRINT @sql;
EXEC (@sql);
现在您将拥有一个包含所有数据的视图,您可以正常查询它。
如果您使用的是没有STRING_AGG
的 SQL 服务器版本,则需要FOR XML PATH
方法。
我也会为您提供解决方案,我们还可以展示如何将其作为存储过程而不是视图来执行:
DECLARE @sql nvarchar(max) =
STUFF(
(SELECT
CAST(NCHAR(10) AS nvarchar(max)) +
N'UNION ALL' +
NCHAR(10) +
N'SELECT ' +
QUOTENAME(p.name, '''') + N' AS name, ' +
p.start_time + N' AS start_time, ' +
p.end_time + N' AS end_time, * FROM ' +
QUOTENAME(p.name)
FROM sqlth_partitions p
FOR XML PATH(''), TYPE
).value('text()[1]', 'nvarchar(max)'),
1, 11, N'');
-- PRINT @sql;
EXEC (@sql);
如您所见,由此创建一个完整的查询非常复杂和困难。
在得到朋友的帮助后在答案下方。 只需与社区分享它可能会有所帮助。
CREATE PROCEDURE dbo.RetrieveData @tagpath NVARCHAR(255),
@begintime BIGINT,
@endtime BIGINT
AS
DECLARE @tagId VARCHAR(50)
SET @tagId = (SELECT id
FROM sqlth_te
WHERE tagpath LIKE @tagpath)
DECLARE @PNAME NVARCHAR(100)
DECLARE @SQL NVARCHAR(max)
DECLARE mycursor CURSOR local fast_forward FOR
SELECT pname AS 'PNAME'
FROM sqlth_partitions
WHERE end_time >= @endtime
AND sqlth_partitions.start_time <= @begintime
OPEN mycursor
FETCH next FROM mycursor INTO @PNAME
SET @SQL = ''
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = @SQL + 'select floatvalue, t_stamp from '
+ @PNAME + ' WHERE tagid = ' + @tagId + ' UNION '
FETCH next FROM mycursor INTO @PNAME
END
SET @SQL = LEFT (@SQL, Len(@sql) - 8)
EXEC(@SQL)
IF Cursor_status('global', 'myCursor') >=- 1
BEGIN
DEALLOCATE mycursor
END
go
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.