简体   繁体   English

来自不同 Historian 表的动态 SQL 查询

[英]Dynamic SQL query from different Historian tables

I have a historian system in SQL Server which saves certain tag values in a table.我在 SQL 服务器中有一个历史系统,它将某些标签值保存在一个表中。

Each month, the system creates a table (partition table) for this historical data as per the below tables.每个月,系统都会根据下表为这些历史数据创建一个表(分区表)。

For example, this table for the month of Feb2021 ( [ sqlt_data_1_2021_02 ] ):例如,此表为 2021 年 2 月 ( [ sqlt_data_1_2021_02 ] ):

在此处输入图像描述

There's another table that owns the partition table's name along with the start and end date for each historical table:还有另一个表拥有分区表的名称以及每个历史表的开始和结束日期:

在此处输入图像描述

I need to get the data for the historized values in [sqlt_data_x_x_x] based on the start/end date.我需要根据开始/结束日期获取 [sqlt_data_x_x_x] 中历史值的数据。 For example: start Date: 10th of Dec 2020 EndDate: 10th of Feb2021 .例如: start Date: 10th of Dec 2020 EndDate: 10th of Feb2021

This means the query should first look in the required partition table which, in this case.这意味着查询应该首先查看所需的分区表,在这种情况下。 is [ sqlt_data_1_2021_02], [ sqlt_data_1_2021_01], [ sqlt_data_1_2020_12] .[ sqlt_data_1_2021_02], [ sqlt_data_1_2021_01], [ sqlt_data_1_2020_12]

Then query will retrieve the date from these three tables and UNION ALL for the results.然后查询将从这三个表中检索日期,并从UNION ALL中检索结果。

How can I do this dynamically, since the start & end dates are variable?我怎样才能动态地做到这一点,因为开始和结束日期是可变的?

I added more clarification about the requirement我添加了有关要求的更多说明

--First Query --第一次查询

select  id from sqlth_te where tagpath like '%tagName%' --tagname is Param for SP

 --Result will be ID=153

Second Query end_time and Start_time as parm in SP第二次查询 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]

The third Query, use the result of above query which gave table names to第三个查询,使用上面查询的结果,它给出了表名

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 required Parameters should be [ EXEC SPname 'tagname',end_time,Start_time ] Sp 所需参数应为 [ EXEC SPname 'tagname',end_time,Start_time ]

One option would be to create a dynamic query that picks up all the tables.一种选择是创建一个获取所有表的动态查询。 But it can be error-prone and difficult to debug.但它可能容易出错且难以调试。

Instead, I think your best bet here is to use dynamic SQL to create a view that contains all the necessary tables aggregated together.相反,我认为您最好的选择是使用动态 SQL 来创建一个视图,其中包含聚合在一起的所有必要表。 We can use a SQL Server Agent job to periodically maintain the view, with this code:我们可以使用 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);

Now you will have a view that contains all the data together, and you can query it as normal.现在您将拥有一个包含所有数据的视图,您可以正常查询它。


If you are using a version of SQL Server that does not have STRING_AGG , you will need the FOR XML PATH method.如果您使用的是没有STRING_AGG的 SQL 服务器版本,则需要FOR XML PATH方法。

I will give you the solution to that also, and we can also show how to do this as a stored procedure instead of a view:我也会为您提供解决方案,我们还可以展示如何将其作为存储过程而不是视图来执行:

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);

As you can see, creating a full query from this is very complex and difficult.如您所见,由此创建一个完整的查询非常复杂和困难。

below the answer after getting help from a friend.在得到朋友的帮助后在答案下方。 just share it with the community may it will help.只需与社区分享它可能会有所帮助。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM