SQL计算列中的更改

时间:2018-02-10 15:18:11

标签: sql sql-server gaps-and-islands

我有来自测量活动水平的加速度计的数据 - 输出是以站立或躺着的每分钟的秒数给出的(参见下表,来自1个人的例子)。

**Date**   **Time**  **Standing** **Lying**
21/02/2017  10:15:00    0      60
21/02/2017  10:16:00    0      60
21/02/2017  10:17:00    0      60
21/02/2017  10:18:00    0      60
21/02/2017  10:19:00    0      60
21/02/2017  10:20:00    0      60
21/02/2017  10:21:00    43     17
21/02/2017  10:22:00    60     0
21/02/2017  10:23:00    60     0
21/02/2017  10:24:00    46     14
21/02/2017  10:25:00    0      60
21/02/2017  10:26:00    0      60
21/02/2017  10:27:00    0      60
21/02/2017  10:28:00    0      60
21/02/2017  10:29:00    0      60
21/02/2017  10:30:00    0      60
21/02/2017  10:31:00    0      60
21/02/2017  10:32:00    0      60

我对每个人每天的活动变化感兴趣。因此,有兴趣计算患者在24小时内从躺卧变为站立的次数 - 例如一段时间的谎言在24小时内发生了多少次 - 但是包括60秒的阈值。例如,如果数据从平躺变为静止只有几秒钟,则可能是假的。

我有兴趣做的第二件事是计算每个(真实)说谎的平均时间,同样在每个人的24小时内计算。

SQL Server中每种方法的最佳方法是什么?

修改

以上问题过于宽泛。我想知道最好的方法来计算躺卧的总次数和平均躺卧时间 - 都是在24小时内

过渡将是从谎言变为站立的任何事物(例如桌子上的10:21:00)或反向 - 站立到谎言(例如10:24:00)

Date Bouts AvBoutTime 
21/2 41    20 
22/2 38    25 
23/2 48    17

2 个答案:

答案 0 :(得分:1)

我在这里只有一个部分答案,但是如果有帮助我会发布它,如果我有其他想法,我可能会调查它。

这是我所拥有的以及SQL小提琴的链接: http://sqlfiddle.com/#!18/72532/27/0

表格结构

CREATE TABLE Activity (
  [Date] varchar(10),
  [Time] varchar(8),
  [Standing] Integer,
  [Lying] Integer
);


INSERT INTO Activity ([Date], [Time], [Standing], [Lying])
VALUES
('21/02/2017', '10:15:00', 0,  60),
('21/02/2017', '10:16:00', 0,  60),
('21/02/2017', '10:17:00', 0,  60),
('21/02/2017', '10:18:00', 0,  60),
('21/02/2017', '10:19:00', 0,  60),
('21/02/2017', '10:20:00', 0,  60),
('21/02/2017', '10:21:00', 43, 17),
('21/02/2017', '10:22:00', 60, 0),
('21/02/2017', '10:23:00', 60, 0),
('21/02/2017', '10:24:00', 46, 14),
('21/02/2017', '10:25:00', 0,  60),
('21/02/2017', '10:26:00', 0,  60),
('21/02/2017', '10:27:00', 0,  60),
('21/02/2017', '10:28:00', 0,  60),
('21/02/2017', '10:29:00', 0,  60),
('21/02/2017', '10:30:00', 0,  60),
('21/02/2017', '10:31:00', 0,  60),
('21/02/2017', '10:32:00', 0,  60)
;

中级表

我创建了一个中间表,我将数据转换为CurrentPostureDuration列。我还添加了PreviousPosture列,以便能够跟踪更改。

CREATE TABLE ActivityPivoted (
  [Date] varchar(10),
  [Time] varchar(8),
  [Duration] Integer,
  [CurrentPosture] varchar(20),
  [PreviousPosture] varchar(20)
);

INSERT INTO ActivityPivoted
select Date,
Time,
Duration,
CurrentPosture,
lag(CurrentPosture, 1, 'N/A') over(order by Time) as 'PreviousPosture'
from (
    select *,
    case when Standing>Lying then 'Standing' else 'Lying' end as CurrentPosture,
    case when Standing>Lying then Standing else Lying end as Duration
    from Activity
) tmp
order by Time

这是它包含的内容:

|       Date |     Time | Duration | CurrentPosture | PreviousPosture |
|------------|----------|----------|----------------|-----------------|
| 21/02/2017 | 10:15:00 |       60 |          Lying |             N/A |
| 21/02/2017 | 10:16:00 |       60 |          Lying |           Lying |
| 21/02/2017 | 10:17:00 |       60 |          Lying |           Lying |
| 21/02/2017 | 10:18:00 |       60 |          Lying |           Lying |
| 21/02/2017 | 10:19:00 |       60 |          Lying |           Lying |
| 21/02/2017 | 10:20:00 |       60 |          Lying |           Lying |
| 21/02/2017 | 10:21:00 |       43 |       Standing |           Lying |
| 21/02/2017 | 10:22:00 |       60 |       Standing |        Standing |
| 21/02/2017 | 10:23:00 |       60 |       Standing |        Standing |
| 21/02/2017 | 10:24:00 |       46 |       Standing |        Standing |
| 21/02/2017 | 10:25:00 |       60 |          Lying |        Standing |
| 21/02/2017 | 10:26:00 |       60 |          Lying |           Lying |
| 21/02/2017 | 10:27:00 |       60 |          Lying |           Lying |
| 21/02/2017 | 10:28:00 |       60 |          Lying |           Lying |
| 21/02/2017 | 10:29:00 |       60 |          Lying |           Lying |
| 21/02/2017 | 10:30:00 |       60 |          Lying |           Lying |
| 21/02/2017 | 10:31:00 |       60 |          Lying |           Lying |
| 21/02/2017 | 10:32:00 |       60 |          Lying |           Lying |

从那里,它可以非常容易地计算姿势变化的数量

select CurrentPosture,
count(*)
from ActivityPivoted
where CurrentPosture<>PreviousPosture
group by CurrentPosture

结果

| CurrentPosture |   |
|----------------|---|
|          Lying | 2 |
|       Standing | 1 |

不幸的是,由于SQL Server没有重置分区的总和,因此我无法对每个状态分区的持续时间求和。例如:

select *,
sum(Duration) over(partition by CurrentPosture order by Time)
from ActivityPivoted
order by Time

结果:

|       Date |     Time | Duration | CurrentPosture | PreviousPosture |     |
|------------|----------|----------|----------------|-----------------|-----|
| 21/02/2017 | 10:15:00 |       60 |          Lying |             N/A |  60 |
| 21/02/2017 | 10:16:00 |       60 |          Lying |           Lying | 120 |
| 21/02/2017 | 10:17:00 |       60 |          Lying |           Lying | 180 |
| 21/02/2017 | 10:18:00 |       60 |          Lying |           Lying | 240 |
| 21/02/2017 | 10:19:00 |       60 |          Lying |           Lying | 300 |
| 21/02/2017 | 10:20:00 |       60 |          Lying |           Lying | 360 |
| 21/02/2017 | 10:21:00 |       43 |       Standing |           Lying |  43 |
| 21/02/2017 | 10:22:00 |       60 |       Standing |        Standing | 103 |
| 21/02/2017 | 10:23:00 |       60 |       Standing |        Standing | 163 |
| 21/02/2017 | 10:24:00 |       46 |       Standing |        Standing | 209 |
| 21/02/2017 | 10:25:00 |       60 |          Lying |        Standing | 420 | < Sum not reset
| 21/02/2017 | 10:26:00 |       60 |          Lying |           Lying | 480 |
| 21/02/2017 | 10:27:00 |       60 |          Lying |           Lying | 540 |
| 21/02/2017 | 10:28:00 |       60 |          Lying |           Lying | 600 |
| 21/02/2017 | 10:29:00 |       60 |          Lying |           Lying | 660 |
| 21/02/2017 | 10:30:00 |       60 |          Lying |           Lying | 720 |
| 21/02/2017 | 10:31:00 |       60 |          Lying |           Lying | 780 |
| 21/02/2017 | 10:32:00 |       60 |          Lying |           Lying | 840 |

答案 1 :(得分:0)

这是 Gaps and Islands 问题

DECLARE @tab TABLE ([Date] DATE, [Time] TIME, Standing INT, Lying INT )
INSERT INTO @tab
(Date, Time, Standing, Lying)
VALUES
('2017-02-21','10:15:00',0,60),
('2017-02-21','10:16:00',0,60),
('2017-02-21','10:17:00',0,60),
('2017-02-21','10:18:00',0,60),
('2017-02-21','10:19:00',0,60),
('2017-02-21','10:20:00',0,60),
('2017-02-21','10:21:00',43,17),
('2017-02-21','10:22:00',60,0),
('2017-02-21','10:23:00',60,0),
('2017-02-21','10:24:00',46,14),
('2017-02-21','10:25:00',0,60),
('2017-02-21','10:26:00',0,60),
('2017-02-21','10:27:00',0,60),
('2017-02-21','10:28:00',0,60),
('2017-02-21','10:29:00',0,60),
('2017-02-21','10:30:00',0,60),
('2017-02-21','10:31:00',0,60),
('2017-02-21','10:32:00',0,60)

SELECT 
      Y.[Date]
    , Bouts     = COUNT(DISTINCT Y.Island) --DISTINCT Islands for number of bouts
    , AvBoutTime=CAST((SUM(Y.Lying)/ (COUNT(DISTINCT Y.Island)* 1.0) ) AS DECIMAL(9,1))
FROM
(
    SELECT
            --Break the dataset down into ISLANDS- using the funky technique
          Island = X.RN - ROW_NUMBER()OVER(PARTITION BY X.Date ORDER BY X.RN)
        , X.[Date]
        , X.[Time]
        , X.Standing
        , X.Lying
    FROM
    (
        SELECT
                --CREATE AN INCREMENTING ID Column like an Identity using ROW_NUmber
                --No need for this if there's already is one just missing from the example shown
              RN = ROW_NUMBER()OVER(PARTITION BY T.[Date] ORDER BY T.[Time] ASC)
            , T.[Date]
            , T.[Time]
            , T.Standing
            , T.Lying 
        FROM @tab T
    ) X
    WHERE X.Lying > 0
) Y
GROUP BY
      Y.[Date]
ORDER BY [Y].[Date]

输出

Date        Bouts   AvBoutTime
2017-02-21  2       435.5