【问题标题】:How to select the continuous data from sqlite file如何从 sqlite 文件中选择连续数据
【发布时间】:2019-11-04 03:43:19
【问题描述】:

我在 SQLite 文件中有一些数据,并且想从 C# 中对其进行操作。

数据包括三列,TimeTemperaturePower。我想找到Temperature大于30,持续时间超过3分钟的记录组,并计算每组的平均功率(连续时间范围)。

Select continuous ranges from table

How to Select continuous date in 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();
            }
        }

【问题讨论】:

    标签: c# sql sqlite linq


    【解决方案1】:

    您正在查看正确的问题,因为这确实是一个差距和孤岛问题。在您的情况下,“岛屿”是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
    

    Demo on dbfiddle

    【讨论】:

    • 这个问题是 3-4 没有运行超过 3 分钟
    • MAX(Time) OVER (PARTITION BY Time AND (Temp > 30) ORDER BY No) maxTime, 很容易添加到CLE (连同最小值).. 但我不知道如何处理 SqlLite 中的 DateDiff 和比较(尽管我认为 SQLiteDataAdapter 可能是这方面的一个方面`
    • @GabrielLlorico 我添加了一个检查时间段是否超过 3 分钟。
    • @BrettCaswell 您可以使用strftime('%s', date) 获取unix时间戳
    • 谢谢..您的解决方案在这里非常好..MIN(Time)CTE 中的选择中的Time 相同吗?在我上面的评论之后,我意识到基于分区的minTime 不会连续工作。
    【解决方案2】:

    我推荐 nick 的回答。

    以下脚本是sql server版本:

    您可以使用temptable + cursor 来执行此操作。

    逻辑:

    • 选择进入创建temptable并过滤Temp > 30
    • 滞后函数获取PreviousNo
    • 运行 corsor 检查PreviousNo = CurrentNo - 1 是否放入同一组
    • 具有时间分钟差异 > 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 行受影响
    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 行受影响
    select * from #T
    GO
    
    上一个没有 |组ID |没有 |时间 |温度 |力量 ---------: | ------: | -: | :----------------- | ---: | ----: 0 | | 3 | 2019 年 4 月 11 日 00:02:20 | 31 | 680 3 | | 4 | 2019 年 4 月 11 日 00:03:30 | 34 | 960 4 | | 6 | 2019 年 4 月 11 日 00:05:50 | 31 | 600 6 | | 7 | 2019 年 4 月 11 日 00:07:00 | 32 | 400 7 | | 8 | 2019 年 4 月 11 日 00:08:10 | 33 | 900 8 | | 9 | 2019 年 4 月 11 日 00:09:20 | 34 | 1000 9 | | 10 | 2019 年 4 月 11 日 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 行受影响
    select * from #T
    GO
    
    上一个没有 |组ID |没有 |时间 |温度 |力量 ---------: | ------: | -: | :----------------- | ---: | ----: 0 | 2 | 3 | 2019 年 4 月 11 日 00:02:20 | 31 | 680 3 | 2 | 4 | 2019 年 4 月 11 日 00:03:30 | 34 | 960 4 | 3 | 6 | 2019 年 4 月 11 日 00:05:50 | 31 | 600 6 | 3 | 7 | 2019 年 4 月 11 日 00:07:00 | 32 | 400 7 | 3 | 8 | 2019 年 4 月 11 日 00:08:10 | 33 | 900 8 | 3 | 9 | 2019 年 4 月 11 日 00:09:20 | 34 | 1000 9 | 3 | 10 | 2019 年 4 月 11 日 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 |平均功率 |分钟 |最大时间 |时差 :------- | --------: | :----------------- | :----------------- | --------: 6 到 10 | 620 | 2019 年 4 月 11 日 00:05:50 | 2019 年 4 月 11 日 00:10:30 | 5

    db小提琴here

    【讨论】:

    • 很多这个答案对 SQLite 无效
    • @Nick,是的,你说得对,我太笨了……我建议你回答。
    • 一点也不傻,这是一个很好的答案,但似乎 OP 想要一个 SQLite 解决方案。
    • 由于我的技术不好,我未能使用翻译的 C# SQLite 方法尝试您的代码,但感谢您的工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-27
    • 1970-01-01
    • 2019-06-28
    • 1970-01-01
    相关资源
    最近更新 更多