查询iHistorian时使用SQL参数

时间:2014-02-13 09:22:38

标签: sql sql-server

我正在使用MS SQL通过链接服务器查询iHistorian。我想循环SQL表中的不同标记名。我遇到的问题是将参数添加到ihistorian查询中。代码如下。我没有在标记名中包含声明,因为此时它不相关。

    SELECT timestamp AS Interval, Left(Right(TagName,Len(TagName)-5),Len(TagName)-10) as TagName,
CONVERT(decimal(10, 3), ROUND(value, 3)) As Value, quality 
FROM 
   OPENQUERY(IHISTORIAN,'
                SET starttime =''yesterday '', endtime =''yesterday +1h''  
                SELECT timestamp, tagname, value, ihRawData.quality 
                FROM ihRawData
                WHERE tagname = '+ @tagname +' 
                AND timestamp BETWEEN ''timestamp'' and ''timestamp'' 
                AND SamplingMode =Calculated
                AND CalculationMode =Average
                AND IntervalMilliseconds =1h
                ORDER BY tagname, timestamp')
                end

我遇到的问题是WHERE tagname = '+ @tagname +'点。该查询不喜欢'+ @tagname +'。它强调了第一个+,并说预期会有)

我基本上想要独立于历史记录查询设置标记名,如前所述。

完整查询 -

use Optimiser_Test;

declare @tagname varchar(32)
--declare @rowcount int
--declare @maxrows int
--select @maxrows = count(*) from OptimiserTags

--set @rowcount = 0

set @tagname = 'UMIS.99FE1100.F_CV'

--while @rowcount < @maxrows
begin


SELECT timestamp AS Interval, Left(Right(TagName,Len(TagName)-5),Len(TagName)-10) as TagName,
CONVERT(decimal(10, 3), ROUND(value, 3)) As Value, quality 
FROM 
   OPENQUERY(IHISTORIAN,'
                SET starttime =''yesterday '', endtime =''yesterday +1h''  
                SELECT timestamp, tagname, value, ihRawData.quality 
                FROM ihRawData
                WHERE tagname = REPLACE(@tagName, '''','')
                AND timestamp BETWEEN ''timestamp'' and ''timestamp'' 
                AND SamplingMode =Calculated
                AND CalculationMode =Average
                AND IntervalMilliseconds =1h
                ORDER BY tagname, timestamp')
                end

NEW UPDATE -

use Optimiser_Test;


declare @tagname varchar(32)
declare @fullquery varchar(1000)

set @fullquery = 'SELECT timestamp AS Interval, Left(Right(TagName,Len(TagName)-5),Len(TagName)-10) as TagName,
CONVERT(decimal(10, 3), ROUND(value, 3)) As Value, quality 
FROM 
   OPENQUERY(IHISTORIAN,
                SET starttime =''yesterday '', endtime =''yesterday +1h''  
                SELECT timestamp, tagname, value, ihRawData.quality 
                FROM ihRawData
                WHERE tagname = '''+ @tagname +'''
                AND timestamp BETWEEN ''timestamp'' and ''timestamp'' 
                AND SamplingMode =Calculated
                AND CalculationMode =Average
                AND IntervalMilliseconds =1h
                ORDER BY tagname, timestamp'''''

begin
set @tagname = 'UMIS.99FE1100.F_CV'
exec (@fullquery)

end

新更新2 -

如果我使用查询中指定的标记名运行查询,如下所示,我得到以下结果。这是正确的。

use Optimiser_Test;

SELECT timestamp AS Interval, Left(Right(TagName,Len(TagName)-5),Len(TagName)-10) as TagName,
CONVERT(decimal(10, 3), ROUND(value, 3)) As Value, quality 
FROM 
   OPENQUERY(IHISTORIAN,'
                SET starttime =''yesterday '', endtime =''yesterday +1h''  
                SELECT timestamp, tagname, value, ihRawData.quality 
                FROM ihRawData
                WHERE tagname = UMIS.99FE1100.F_CV
                AND timestamp BETWEEN ''timestamp'' and ''timestamp'' 
                AND SamplingMode =Calculated
                AND CalculationMode =Average
                AND IntervalMilliseconds =1h
                ORDER BY tagname, timestamp')

结果

enter image description here

经过与James S的多次来回和与我的同事的进一步合作之后,我得到了回报我需要的东西。

Declare @SQLString varchar(1000)
Declare @TAGS VarChar(1000)

Set @Tags = '"UMIS.99FE1100.F_CV"'

SET @SQLString = 'SELECT timestamp AS Interval, Left(Right(TagName,Len(TagName)-5),Len(TagName)-10) as TagName,
CONVERT(decimal(10, 3), ROUND(value, 3)) As Value, quality 
FROM 
   OPENQUERY(IHISTORIAN,''
                SET starttime =''''yesterday '''', endtime =''''yesterday +1h'''',
                         SELECT timestamp, tagname, value, ihRawData.quality 
                FROM ihRawData
                WHERE tagname = ' + @Tags + '
                           and IntervalMilliseconds =1h,  
                           and CalculationMode =Average,
                           and SamplingMode =Calculated
                ORDER BY tagname, timestamp'')
                           '

Print @SQLString
Print @Tags
Exec (@SQLString)

1 个答案:

答案 0 :(得分:1)

你的问题是缺少@tagname周围的引号(假设它是一个字符串) 但是我认为除了那个之外还有其他语法问题!

但是有没有理由使用OPENQUERY,而不是仅通过它的四个部分名称直接执行SQL引用源表:server.database.schema.table?

无论如何你应该换行:WHERE tagname = '+ @tagname +'WHERE tagname = '''+ @tagname +'''以修复现有查询。

这当然是假设@tagName不是用户输入的,否则你会对SQL注入攻击持开放态度。您可以使用REPLACE(@tagName, '''','')代替@tagName来解决此问题,但直接查询会更加安全......

直接查询示例:

SET starttime ='yesterday', endtime ='yesterday +1h'

SELECT timestamp AS Interval, 
       Left(Right(TagName,Len(TagName)-5),Len(TagName)-10) as TagName,
       CONVERT(decimal(10, 3), ROUND(value, 3)) As Value, 
       quality 
FROM IHISTORIAN.<dbname>.dbo.ihRawData
    WHERE tagname = @tagname 
        AND timestamp BETWEEN 'timestamp' and 'timestamp' 
        AND SamplingMode ='Calculated'
        AND CalculationMode ='Average'
        AND IntervalMilliseconds ='1h'
    ORDER BY tagname, timestamp

修改

更正了OPENQUERY示例:(但不确定行SET starttime =''yesterday '', endtime =''yesterday +1h''的用途是什么,所以这已被删除!)NB - 我假设SamplingMode,CalculationMode和IntervalMilliseconds应该是字符串,并将它们包含在转义引用中太。现在,整个SQL字符串首先构造成一个变量,然后再将其传递给OPENQUERY

use Optimiser_Test;

declare @tagname varchar(32)
DECLARE @startTimeStamp NVARCHAR(50), @endTimeStamp NVARCHAR(50)
DECLARE @sql NVARCHAR(8000)
--declare @rowcount int
--declare @maxrows int
--select @maxrows = count(*) from OptimiserTags

--set @rowcount = 0

set @tagname = 'UMIS.99FE1100.F_CV'

--while @rowcount < @maxrows
begin

SET @startTimeStamp = 'yesterday'
SET @endTimeStamp = 'yesterday +1h'
SET @sql =     'SELECT timestamp, tagname, value, ihRawData.quality 
                FROM ihRawData
                WHERE tagname = ''' + REPLACE(@tagName, '''','') + '''
                AND timestamp BETWEEN ''' + @startTimeStamp + ''' 
                              AND ''' + @endTimeStamp + '''  
                AND SamplingMode =''Calculated''
                AND CalculationMode =''Average''
                AND IntervalMilliseconds =''1h''
                ORDER BY tagname, timestamp'

SELECT timestamp AS Interval, Left(Right(TagName,Len(TagName)-5),Len(TagName)-10) as TagName,
CONVERT(decimal(10, 3), ROUND(value, 3)) As Value, quality 
FROM 
   OPENQUERY(IHISTORIAN, @sql)
                end

编辑2

好的 - 如果您的最终查询得到了您想要的内容,那么您需要做的就是声明一个NVARCHAR变量 - 用SQL填充它,然后将该变量传递给openQuery。我不认为你可以在函数调用的()内动态构建字符串。

IE:

use Optimiser_Test;

declare @tagname varchar(32)
set @tagname = 'UMIS.99FE1100.F_CV'

DECLARE @SQL NVARCHAR(4000)
SET @SQL = 'SET starttime =''yesterday '', endtime =''yesterday +1h''  
                SELECT timestamp, tagname, value, ihRawData.quality 
                FROM ihRawData
                WHERE tagname = ' + @tagname + '
                AND timestamp BETWEEN ''timestamp'' and ''timestamp'' 
                AND SamplingMode =Calculated
                AND CalculationMode =Average
                AND IntervalMilliseconds =1h
                ORDER BY tagname, timestamp'
SELECT timestamp AS Interval, Left(Right(TagName,Len(TagName)-5),Len(TagName)-10) as TagName,
CONVERT(decimal(10, 3), ROUND(value, 3)) As Value, quality 
FROM 
   OPENQUERY(IHISTORIAN,@SQL)