Simple-Scada forum

Simple-Scada 2 => Ваши вопросы => Тема начата: SergeyP от 10 Сентября 2024, 15:09:59

Название: Выборка значений из БД через union
Отправлено: SergeyP от 10 Сентября 2024, 15:09:59
Добрый день.
Имеется база данных трендов с значениями датчиков. Требуется выбрать минимальное, максимально и среднее значение из базы по нескольким датчикам и группе датчиков за заданный период времени.

Если делать выборку одним простым запрсом SELECT - проблем нет, данные все получаю, передаю в отчет. Код вот такой:

Код: (delphi)
var

  aQuery: string;               // сам запрос
  aFromStr, aToStr: string;     // интервал времени в виде строки

begin

 aFromStr := MySQLDateTime(DATA_BEGIN.VALUE, dttFull);
 aToStr   := MySQLDateTime(DATA_END.VALUE, dttFull);

   aQuery := 'SELECT TRUNCATE(MIN(`V`), 2), TRUNCATE(MAX(`V`), 2), TRUNCATE(AVG(`V`), 2) ' +
              'FROM `trends` ' +
              'WHERE (`t` >= ' + aFromStr + ') AND (`t` <= ' + aToStr + ') AND ' +
              '((`id` = 21) or (`id` = 23) or (`id` = 25))';
 
RunSQL(aQuery, nil, 1);

end.

Для получения данных по нескольким датчикам использую UNION. Код вот такой тогда использую:

Код: (delphi)
var

  aQuery: string;               // сам запрос
  aFromStr, aToStr: string;     // интервал времени в виде строки

begin

 aFromStr := MySQLDateTime(DATA_BEGIN.VALUE, dttFull);
 aToStr   := MySQLDateTime(DATA_END.VALUE, dttFull);

   aQuery := 'SELECT TRUNCATE(MIN(`V`), 2), TRUNCATE(MAX(`V`), 2), TRUNCATE(AVG(`V`), 2) ' +
              'FROM `trends` ' +
              'WHERE (`t` >= ' + aFromStr + ') AND (`t` <= ' + aToStr + ') AND ' +
              '((`id` = 21) or (`id` = 23) or (`id` = 25))'  +
              'union' +
              'SELECT TRUNCATE(MIN(`V`), 2), TRUNCATE(MAX(`V`), 2), TRUNCATE(AVG(`V`), 2) ' +
              'FROM `trends` ' +
              'WHERE (`t` >= ' + aFromStr + ') AND (`t` <= ' + aToStr + ') AND ' +
              '(`id` = 11)' +
              'union' +
              'SELECT TRUNCATE(MIN(`V`), 2), TRUNCATE(MAX(`V`), 2), TRUNCATE(AVG(`V`), 2) ' +
              'FROM `trends` ' +
              'WHERE (`t` >= ' + aFromStr + ') AND (`t` <= ' + aToStr + ') AND ' +
              '(`id` = 10);';

  RunSQL(aQuery, nil, 1);

end.

Для обработки данных использую скрипт "Выполнен SQL запрос". Вот такой

 
Код: (delphi)
var

 aReport: TM_Report;

begin

  if DataSet.IsEmpty then Exit;
 
  if DataSet.Tag = 1 then
  begin
    MIN_room1.Value := DataSet.Fields[0].AsStr;
    MAX_room1.Value := DataSet.Fields[1].AsStr;
    AVG_room1.Value := DataSet.Fields[2].AsStr;
    MIN_T_room1.Value := DataSet.Fields[3].AsStr;
    MAX_T_room1.Value := DataSet.Fields[4].AsStr;
    AVG_T_room1.Value := DataSet.Fields[5].AsStr;
    MIN_HE_room1.Value := DataSet.Fields[6].AsStr;
    MAX_HE_room1.Value := DataSet.Fields[7].AsStr;
    AVG_HE_room1.Value := DataSet.Fields[8].AsStr;
    end;

  aReport := ReportBuild('Камера газации 1');
  aReport.View(GetClientName);
                                           
end.

Для простой выборки через SELECT - все работает.  При применении UNION - не работает.

Подскажите, к в чем может быть проблема с запросом к базе? Или как реализовать по нажатию кнопки выполнение нескольких запросов с последующей передачей данных в переменные и отчет.


Название: Re: Выборка значений из БД через union
Отправлено: Simple_Scada от 12 Сентября 2024, 12:59:30
Здравствуйте.

Цитировать
Требуется выбрать минимальное, максимально и среднее значение из базы по нескольким датчикам и группе датчиков за заданный период времени. ...как реализовать по нажатию кнопки выполнение нескольких запросов с последующей передачей данных в переменные и отчет.
Если указанные данные нужны для построения отчета, то для решения задачи не требуется использовать скрипты и SQL-запросы.

Вы можете создать периодический отчет (https://simple-scada.com/help/report/per-rep.html) и на шаге добавления переменной в источник (https://clck.ru/3DE6yL) выбрать соответствующий "тип обработки (https://clck.ru/3DFCKN)" -> "минимум", "максимум" или "среднее". Далее переменной интервала "Данные_Интервал (https://simple-scada.com/help/report/per-rep.html#:~:text=%D0%9D%D0%B0%D0%B6%D0%BC%D0%B5%D0%BC%20%D0%BA%D0%BD%D0%BE%D0%BF%D0%BA%D1%83%20%22%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D1%8C,%D0%BF%D0%BE%D0%BF%D0%B0%D0%B4%D1%83%D1%82%20%D0%B2%20%D0%B8%D1%81%D1%82%D0%BE%D1%87%D0%BD%D0%B8%D0%BA.)" нужно задать значение равное 0, тогда вычисления будут производиться за весь период времени, без разбивки на интервалы. Теперь полученные переменные можно перетащить на страницу отчета (см. скриншот во вложении). В итоге, при построении отчета в эти переменные будет выводиться минимум, максимум и среднее за необходимый промежуток времени. Перед вызовом построения отчета нужно задать требуемый интервал времени через соответствующие переменные - в примере это переменные "vrTimeBegin" и "vrTimeEnd" (https://simple-scada.com/help/report/per-rep.html#:~:text=%D0%9C%D1%8B%20%D1%85%D0%BE%D1%82%D0%B8%D0%BC%20%D1%87%D1%82%D0%BE%D0%B1%D1%8B,%D0%A1%D0%B2%D1%8F%D0%B7%D0%B0%D1%82%D1%8C%20%D1%81%20%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9%22%3A).

Дополнительные рекомендации:
1. При формировании SQL-запросов к штатной БД необходимо указывать нужный слой архива для выборки - см. описание колонки "l" (https://simple-scada.com/help/manual/tablestruct.html). Это позволит исключить лишние данные. В Вашем случае, можно было использовать основной слой.
2. Данные, полученные через приведенные SQL-запросы могут быть некорректными, особенно это касается вычисления среднего. Через SQL-запрос Вы получите среднее арифметическое точек архива за указанный интервал времени. Данный результат точно будет неправильным, т.к. для корректного вычисления среднего по архивным данным, необходимо учитывать длительность нахождения переменной в каждом значении. Поэтому в отчетах используется вычисление средневзвешенного по времени значения.