Повесить триггер на History нельзя, поскольку это не настоящая таблица SQL Server-а, а сами данные идут напрямую в Storage-процесс.
Event-система хисториана - непонятно почему ещё живой глюкавый динозавр, основанный на поллинге данных. Поймать факт превышения предела значения - можно, но вот поймать факт получения значения - только через одно место (нетривиальный запрос с определением изменения числа состояний в секундном интервале начинающемся две секунды назад). Понятно почему - значения тэга это непрерывный сигнал..ну дальше вы поняли.
Поэтому пока Invensys не проснётся наконец и не переделает Event систему хисториана на PUSH-метод с возможностями легко подцеплять запуск процессов, .NET сборок, и т.д., я бы рекомендовал написать, например, вот такую программу
:
- Код: Выделить всё
using System;
using System.Data.SqlClient;
using System.Threading;
namespace TagChangeDetector
{
class Program
{
private static String GetUserConnectionString()
{
SqlConnectionStringBuilder sb = new SqlConnectionStringBuilder();
sb.DataSource = ".";
sb.InitialCatalog = "Runtime";
sb.IntegratedSecurity = true;
return sb.ToString();
}
private static void TagChangeDetected(String tagName, String value, DateTime time, Int32 opcQuality, Int32 qualityDetail)
{
Console.WriteLine("New value received for tag {0}: {1} {2} {3} {4}",
tagName, time.ToString("yyyy-MM-dd HH:mm:ss.fff"), value, opcQuality, qualityDetail);
}
static void Main(string[] args)
{
if (args.Length != 2)
{
Console.WriteLine("\nUsage:\n\tTagChangeDetector <tag_name> <polling_interval_in_milliseconds>\n");
return;
}
try
{
String tagName = args[0];
Int32 nSleepMilliseconds = Int32.Parse(args[1]);
String lastKnownValue = String.Empty;
DateTime lastKnownTime = DateTime.Now;
Int32 lastKnownOpcQuality = 0;
Int32 lastKnownQualityDetail = 0;
using (SqlConnection conn = new SqlConnection(GetUserConnectionString()))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = String.Format(
"select DateTime, Value, OPCQuality, QualityDetail from Live where TagName = '{0}'",
tagName);
while (true)
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
String value = reader["Value"].ToString();
DateTime time = (DateTime)reader["DateTime"];
Int32 opcQuality = (Int32) reader["OPCQuality"];
Int32 qualityDetail = (Int32) reader["QualityDetail"];
if (value != lastKnownValue ||
time != lastKnownTime ||
opcQuality != lastKnownOpcQuality ||
qualityDetail != lastKnownQualityDetail)
{
TagChangeDetected(tagName, value, time, opcQuality, qualityDetail);
lastKnownValue = value;
lastKnownTime = time;
lastKnownOpcQuality = opcQuality;
lastKnownQualityDetail = qualityDetail;
}
}
}
Thread.Sleep(nSleepMilliseconds);
}
}
}
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
}
}
}