Как выбрать непрерывные данные из файла sqlite - PullRequest
0 голосов
/ 04 ноября 2019

У меня есть некоторые данные в файлах SQLite, и я хочу манипулировать ими из C #.

Данные состоят из трех столбцов: Time, Temperature и Power. И я хочу найти группы записей, которые имеют Temperature выше 30, и длятся более 3 минут, и вычислить среднее значение мощности каждой группы (непрерывный диапазон времени).

Выберите непрерывные диапазоны из таблицы

Как выбрать непрерывную дату в sql

Я нашел два ответа выше, но не могу найти мой ответ.

Результаты могут быть получены напрямую с помощью строки SQL (для SQLiteDataAdapter). или выберите все данные и манипулируйте ими с помощью c # (datatable.Select, Computer или LINQ).

| No   | Time              | Temp | Power |
| ---- | ----------------- | ---- | ----- |
| 1    | 2019-11-4 0:00:00 | 25   | 1200  |
| 2    | 2019-11-4 0:01:10 | 30   | 1000  |
| 3    | 2019-11-4 0:02:20 | 31   | 680   |
| 4    | 2019-11-4 0:03:30 | 34   | 960   |
| 5    | 2019-11-4 0:04:40 | 29   | 800   |
| 6    | 2019-11-4 0:05:50 | 31   | 600   |
| 7    | 2019-11-4 0:07:00 | 32   | 400   |
| 8    | 2019-11-4 0:08:10 | 33   | 900   |
| 9    | 2019-11-4 0:09:20 | 34   | 1000  |
| 10   | 2019-11-4 0:10:30 | 39   | 200   |
| 11   | 2019-11-4 0:11:40 | 24   | 350   |

Ожидаемые результаты: выберите непрерывные записи, когда Temp больше 30 и непрерывное время больше 3 минуткак группа, и вычислите среднее значение Power.

Одна группа в таблице примера, включающая Нет от 6 до 10. И среднее значение составляет 620.


Спасибо всем.Коды, используемые в моих работах:

        string sql = "WITH CTE AS (" +
                     "SELECT(Temp > 30) AS tempgt30,Time, Power," +
                            "ROW_NUMBER() OVER(ORDER BY No) rn," +
                            "ROW_NUMBER() OVER(PARTITION BY(Temp > 30) ORDER BY No) rn2" +
                     " FROM data" +
                     ")" +
                    " SELECT MIN(rn)AS minrow,MAX(rn) as maxrow," +
                            "strftime('%s', MAX(Time)) - strftime('%s', MIN(Time)) AS duration," +
                            "AVG(Power) AS mean" +
                    " FROM CTE" +
                    " WHERE tempgt30" +
                    " GROUP BY(rn2 - rn)" +
                    " HAVING duration > 180;";

        con.Open();

        if (con.State == ConnectionState.Open)
        {
            using (SQLiteDataAdapter dataAdapter = new SQLiteDataAdapter(sql, con))
            {
                dataAdapter.Fill(datatable);
                con.Close();
            }
        }

Ответы [ 2 ]

4 голосов
/ 04 ноября 2019

Вы искали правильные вопросы, так как это действительно проблема пробелов и островков. В вашем случае «острова» - это показания, где Temp > 30. Мы можем сформировать их и вычислить среднее значение Power и продолжительность острова (в секундах), используя этот запрос:

WITH CTE AS (
SELECT (Temp > 30) AS tempgt30, 
       Time,
       Power,
       ROW_NUMBER() OVER (ORDER BY No) rn,
       ROW_NUMBER() OVER (PARTITION BY (Temp > 30) ORDER BY No) rn2
FROM data
)
SELECT MIN(rn) AS minrow, 
       MAX(rn) as maxrow, 
       MIN(Time) AS start,
       MAX(Time) AS end,
       strftime('%s', MAX(Time)) - strftime('%s', MIN(Time)) AS duration,
       AVG(Power) AS mean
FROM CTE
WHERE tempgt30
GROUP BY (rn2 - rn)
HAVING duration > 180

Вывод:

minrow  maxrow  start                   end                     duration    mean
6       10      2019-11-04 00:05:50     2019-11-04 00:10:30     280         620

Демо на dbfiddle

2 голосов
/ 04 ноября 2019

Я рекомендую ответ Ника.

и ниже сценарий - версия сервера sql:

вы можете использовать temptable + cursor, чтобы сделать это.

логика:

  • выберите для создания temptable и фильтра Temp > 30
  • функция запаздывания get PreviousNo
  • запустите corsor, чтобы проверить, если PreviousNo = CurrentNo - 1 затем положить в ту же группу
  • группу, имеющую время в минутах diff> 3 для получения данных;

CREATE TABLE T
  ([No] int, [Time] datetime, [Temp] int, [Power] int)
;

INSERT INTO T
  ([No], [Time], [Temp], [Power])
VALUES
  (1, '2019-11-04 00:00:00', 25, 1200),
  (2, '2019-11-04 00:01:10', 30, 1000),
  (3, '2019-11-04 00:02:20', 31, 680),
  (4, '2019-11-04 00:03:30', 34, 960),
  (5, '2019-11-04 00:04:40', 29, 800),
  (6, '2019-11-04 00:05:50', 31, 600),
  (7, '2019-11-04 00:07:00', 32, 400),
  (8, '2019-11-04 00:08:10', 33, 900),
  (9, '2019-11-04 00:09:20', 34, 1000),
  (10, '2019-11-04 00:10:30', 39, 200),
  (11, '2019-11-04 00:11:40', 24, 350)
;

GO
11 rows affected
with cte as (
  select 
   LAG(No, 1,0) OVER (ORDER BY No) AS PreviousNo,
   null AS GroupId,
   *
  from T
  where Temp > 30 
)
select * into #T from cte;
GO
7 rows affected
select * from #T
GO
PreviousNo | GroupId | No | Time                | Temp | Power
---------: | ------: | -: | :------------------ | ---: | ----:
         0 |    <em>null</em> |  3 | 04/11/2019 00:02:20 |   31 |   680
         3 |    <em>null</em> |  4 | 04/11/2019 00:03:30 |   34 |   960
         4 |    <em>null</em> |  6 | 04/11/2019 00:05:50 |   31 |   600
         6 |    <em>null</em> |  7 | 04/11/2019 00:07:00 |   32 |   400
         7 |    <em>null</em> |  8 | 04/11/2019 00:08:10 |   33 |   900
         8 |    <em>null</em> |  9 | 04/11/2019 00:09:20 |   34 |  1000
         9 |    <em>null</em> | 10 | 04/11/2019 00:10:30 |   39 |   200
DECLARE @tmp_no int,@groupId int = 1;

DECLARE MY_CURSOR CURSOR 
  LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR 
SELECT No 
FROM #T

OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO @tmp_no
WHILE @@FETCH_STATUS = 0
BEGIN 
    if not (( select PreviousNo from #T where No = @tmp_no ) = @tmp_no - 1)  begin
       set @groupId = @groupId + 1;
    end
    update #T set groupId = @groupId where no = @tmp_no;
    FETCH NEXT FROM MY_CURSOR INTO @tmp_no
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
GO
7 rows affected
select * from #T
GO
PreviousNo | GroupId | No | Time                | Temp | Power
---------: | ------: | -: | :------------------ | ---: | ----:
         0 |       2 |  3 | 04/11/2019 00:02:20 |   31 |   680
         3 |       2 |  4 | 04/11/2019 00:03:30 |   34 |   960
         4 |       3 |  6 | 04/11/2019 00:05:50 |   31 |   600
         6 |       3 |  7 | 04/11/2019 00:07:00 |   32 |   400
         7 |       3 |  8 | 04/11/2019 00:08:10 |   33 |   900
         8 |       3 |  9 | 04/11/2019 00:09:20 |   34 |  1000
         9 |       3 | 10 | 04/11/2019 00:10:30 |   39 |   200
select 
   convert(varchar(3),min(no)) + ' to ' + convert(varchar(3),max(no)) as no_range
   ,avg(power) as avgpower
   ,min(Time) as mintime
   ,max(Time) as maxtime
   , datediff(minute,min(Time),max(Time)) timediff
from #T
group by groupid having datediff(minute,min(Time),max(Time)) > 3
GO
no_range | avgpower | mintime             | maxtime             | timediff
:------- | -------: | :------------------ | :------------------ | -------:
6 to 10  |      620 | 04/11/2019 00:05:50 | 04/11/2019 00:10:30 |        5

db <> скрипка здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...