1

これらの温度測定値を連続したグループの範囲にグループ化する方法はありますか? グループ、時差、カウントを 0 ~ 7 と 8 ~ 12 の間、および 12 以上で取得したい

      Date         Heat 
01/01/2012 12:00    8
01/01/2012 12:03    9
01/01/2012 12:06    5
01/01/2012 12:09    3
01/01/2012 12:12    6
01/01/2012 12:15    7
01/01/2012 12:18    1
01/01/2012 12:21    12
01/01/2012 12:24    28
01/01/2012 12:27    25
01/01/2012 12:30    20
01/01/2012 12:33    20
01/01/2012 12:36    20
01/01/2012 12:39    12
01/01/2012 12:42    6
01/01/2012 12:45    3
01/01/2012 12:48    5
01/01/2012 12:51    7
01/01/2012 12:54    11
01/01/2012 12:57    12
01/01/2012 13:00    6

結果は次のようになります。

0-7   (01/01/2012 12:06-01/01/2012 12:18)   5
/* Rows of dataset:
01/01/2012 12:06    5
01/01/2012 12:09    3
01/01/2012 12:12    6
01/01/2012 12:15    7
01/01/2012 12:18    1    
*/
0-7   (01/01/2012 12:42-01/01/2012 12:51)   5
/* Rows of dataset:
01/01/2012 12:42    6
01/01/2012 12:45    3
01/01/2012 12:48    5
01/01/2012 12:51    7  
*/
8-12   (01/01/2012 12:00-01/01/2012 12:03)   2
/* Rows of dataset:
01/01/2012 12:00    8
01/01/2012 12:03    9
*/
more then 12   (01/01/2012 12:24-01/01/2012 12:36)   5
/* Rows of dataset:
01/01/2012 12:24    28
01/01/2012 12:27    25
01/01/2012 12:30    20
01/01/2012 12:33    20
01/01/2012 12:36    20
*/

8-12   (01/01/2012 12:21)   1
/* Rows of dataset:
01/01/2012 12:21    12     */
4

3 に答える 3

4

注: の処理順序RANK/DENSE_RANKは でありPARTITION BY、次にであるためORDER BY、これらの関数はこの場合には役に立ちません。おそらく、ある時点で、MS は補足的な構文を導入するでしょう: [DENSE_]RANK() OVER(ORDER BY fields PARTITION BY fields)soORDER BYが最初に処理され、次にPARTITION BY.

1) 最初の解決策 (SQL2005+)

    DECLARE @TestData TABLE
    (
        Dt      SMALLDATETIME PRIMARY KEY,
        Heat    TINYINT NOT NULL
    );

    INSERT  @TestData(Dt, Heat)
    VALUES
            SELECT '2012-01-01T12:00:00', 8  UNION ALL SELECT '2012-01-01T12:03:00', 9  UNION ALL SELECT '2012-01-01T12:06:00', 5
UNION ALL   SELECT '2012-01-01T12:09:00', 3  UNION ALL SELECT '2012-01-01T12:12:00', 6  UNION ALL SELECT '2012-01-01T12:15:00', 7
UNION ALL   SELECT '2012-01-01T12:18:00', 1  UNION ALL SELECT '2012-01-01T12:21:00', 12 UNION ALL SELECT '2012-01-01T12:24:00', 28
UNION ALL   SELECT '2012-01-01T12:27:00', 25 UNION ALL SELECT '2012-01-01T12:30:00', 20 UNION ALL SELECT '2012-01-01T12:33:00', 20
UNION ALL   SELECT '2012-01-01T12:36:00', 20 UNION ALL SELECT '2012-01-01T12:39:00', 12 UNION ALL SELECT '2012-01-01T12:42:00', 6
UNION ALL   SELECT '2012-01-01T12:45:00', 3  UNION ALL SELECT '2012-01-01T12:48:00', 5  UNION ALL SELECT '2012-01-01T12:51:00', 7
UNION ALL   SELECT '2012-01-01T12:54:00', 11 UNION ALL SELECT '2012-01-01T12:57:00', 12 UNION ALL SELECT '2012-01-01 13:00:00', 6;

    SET STATISTICS IO ON;

    WITH CteSource
    AS
    (
            SELECT  a.*,
                    CASE 
                        WHEN a.Heat >= 0 AND a.Heat <= 7 THEN 1
                        WHEN a.Heat >= 8 AND a.Heat <= 12 THEN 2
                        WHEN a.Heat > 12 THEN 3
                    END AS Grp,
                    ROW_NUMBER() OVER(ORDER BY a.Dt) AS RowNum
            FROM    @TestData a
    ),  CteRecursive
    AS
    (
            SELECT  s.RowNum,
                    s.Dt,
                    s.Heat,
                    s.Grp,
                    1 AS DENSE_RANK_OVER_ORDERBY_PARTITIONBY
            FROM    CteSource s
            WHERE   s.RowNum = 1
            UNION ALL
            SELECT  crt.RowNum,
                    crt.Dt,
                    crt.Heat,
                    crt.Grp,
                    CASE 
                        WHEN crt.Grp = prev.Grp THEN prev.DENSE_RANK_OVER_ORDERBY_PARTITIONBY 
                        ELSE prev.DENSE_RANK_OVER_ORDERBY_PARTITIONBY + 1
                    END
            FROM    CteSource crt
            INNER JOIN CteRecursive prev ON crt.RowNum = prev.RowNum + 1
    )
    SELECT  r.DENSE_RANK_OVER_ORDERBY_PARTITIONBY, 
            MAX(r.Grp) AS Grp,
            COUNT(*) AS Cnt,
            MIN(r.Dt) AS MinDt,
            MAX(r.Dt) AS MaxDt
    FROM    CteRecursive r
    GROUP BY r.DENSE_RANK_OVER_ORDERBY_PARTITIONBY;

結果:

DENSE_RANK_OVER_ORDERBY_PARTITIONBY Grp         Cnt         MinDt                   MaxDt
----------------------------------- ----------- ----------- ----------------------- -----------------------
1                                   2           2           2012-01-01 12:00:00     2012-01-01 12:03:00
2                                   1           5           2012-01-01 12:06:00     2012-01-01 12:18:00
3                                   2           1           2012-01-01 12:21:00     2012-01-01 12:21:00
4                                   3           5           2012-01-01 12:24:00     2012-01-01 12:36:00
5                                   2           1           2012-01-01 12:39:00     2012-01-01 12:39:00
6                                   1           4           2012-01-01 12:42:00     2012-01-01 12:51:00
7                                   2           2           2012-01-01 12:54:00     2012-01-01 12:57:00
8                                   1           1           2012-01-01 13:00:00     2012-01-01 13:00:00

2) 2 番目の解決策 (SQL2012; パフォーマンスの向上)

SELECT  d.DENSE_RANK_OVER_ORDERBY_PARTITIONBY,
        MAX(d.Grp) AS Grp,
        MIN(d.Dt) AS MinDt,
        MAX(d.Dt) AS MaxDt
FROM
(
        SELECT  c.*,
                1+SUM(c.IsNewGroup) OVER(ORDER BY c.Dt) AS DENSE_RANK_OVER_ORDERBY_PARTITIONBY
        FROM
        (
                SELECT  b.*,
                        CASE 
                            WHEN LAG(b.Grp) OVER(ORDER BY b.Dt) <> b.Grp THEN 1  
                            ELSE 0
                        END
                        AS IsNewGroup
                FROM    
                (
                        SELECT  a.*,
                                CASE 
                                    WHEN a.Heat >= 0 AND a.Heat <= 7 THEN 1
                                    WHEN a.Heat >= 8 AND a.Heat <= 12 THEN 2
                                    WHEN a.Heat > 12 THEN 3
                                END AS Grp
                        FROM    @TestData a
                ) b
        ) c
) d
GROUP BY d.DENSE_RANK_OVER_ORDERBY_PARTITIONBY;
于 2012-04-06T10:50:25.650 に答える
1

SQL Server 2005 以降のバージョンの代替ソリューションを次に示します。

WITH auxiliary (HeatID, MinHeat, MaxHeat, HeatDescr) AS (
  SELECT 1, 0 , 7   , '0-7'  UNION ALL
  SELECT 2, 8 , 12  , '8-12' UNION ALL
  SELECT 3, 13, NULL, 'more than 12'
),
datagrouped AS (
  SELECT
    d.*,
    a.HeatDescr,
    grp = ROW_NUMBER() OVER (                      ORDER BY d.Date)
        - ROW_NUMBER() OVER (PARTITION BY a.HeatID ORDER BY d.Date)
  FROM data d
    INNER JOIN auxiliary a
      ON d.Heat BETWEEN a.MinHeat AND ISNULL(a.MaxHeat, 0x7fffffff)
)
SELECT
  HeatDescr,
  DateFrom  = MIN(Date),
  DateTo    = MAX(Date),
  ItemCount = COUNT(*)
FROM datagrouped
GROUP BY
  HeatDescr, grp
ORDER BY
  MIN(Date)

は次dataのように定義されます。

CREATE TABLE data (Date datetime, Heat int);

INSERT INTO data (Date, Heat)
SELECT '01/01/2012 12:00',  8  UNION ALL
SELECT '01/01/2012 12:03',  9  UNION ALL
SELECT '01/01/2012 12:06',  5  UNION ALL
SELECT '01/01/2012 12:09',  3  UNION ALL
SELECT '01/01/2012 12:12',  6  UNION ALL
SELECT '01/01/2012 12:15',  7  UNION ALL
SELECT '01/01/2012 12:18',  1  UNION ALL
SELECT '01/01/2012 12:21',  12 UNION ALL
SELECT '01/01/2012 12:24',  28 UNION ALL
SELECT '01/01/2012 12:27',  25 UNION ALL
SELECT '01/01/2012 12:30',  20 UNION ALL
SELECT '01/01/2012 12:33',  20 UNION ALL
SELECT '01/01/2012 12:36',  20 UNION ALL
SELECT '01/01/2012 12:39',  12 UNION ALL
SELECT '01/01/2012 12:42',  6  UNION ALL
SELECT '01/01/2012 12:45',  3  UNION ALL
SELECT '01/01/2012 12:48',  5  UNION ALL
SELECT '01/01/2012 12:51',  7  UNION ALL
SELECT '01/01/2012 12:54',  11 UNION ALL
SELECT '01/01/2012 12:57',  12 UNION ALL
SELECT '01/01/2012 13:00',  6;

上記のサンプルの場合、クエリは次の出力を提供します。

HeatDescr     DateFrom             DateTo               ItemCount 
------------  -------------------  -------------------  --------- 
8-12          2012-01-01 12:00:00  2012-01-01 12:03:00  2    
0-7           2012-01-01 12:06:00  2012-01-01 12:18:00  5    
8-12          2012-01-01 12:21:00  2012-01-01 12:21:00  1    
more than 12  2012-01-01 12:24:00  2012-01-01 12:36:00  5    
8-12          2012-01-01 12:39:00  2012-01-01 12:39:00  1    
0-7           2012-01-01 12:42:00  2012-01-01 12:51:00  4    
8-12          2012-01-01 12:54:00  2012-01-01 12:57:00  2    
0-7           2012-01-01 13:00:00  2012-01-01 13:00:00  1    
于 2012-04-07T09:37:52.500 に答える