在sql中选择一个不同的属性,但仅限于时间间隔

时间:2016-06-08 12:59:22

标签: sql sql-server

我在SQL中有这个表有多个列

日期时间,用户名,读取ID

我需要计算表中不同读取ID的数量,但只计算10分钟间隔

例如,如果我的表看起来像这样

1 2016/06/08 15:49:10.000 user1 5859
2 2016/06/08 15:48:39.000 user1 5859
3 **2016/06/08 15:47:53.000 user3 5859**
4 **2016/06/08 15:35:58.000 user1 5859**

我希望它返回2,因为在示例中1 2和3不是相隔10分钟但是3和4是

例如,如果我的表看起来像这样

1 2016/06/08 15:49:10.000 user1 5859
2 2016/06/08 15:48:39.000 user1 5859
3 **2016/06/08 15:47:53.000 user3 5859**

但为此,它将返回1,因为它们相距不到10分钟

本质上我希望它依赖于不同的读取ID,但前提是它们相隔超过10分钟 我不介意使用固定的时间间隔(1:00,1:10,1:20 ......等)

所以我知道我可以对我的读取ID做一个明确的但是那么整个表是否有办法模仿一个​​独特的但只是时间间隔?

2 个答案:

答案 0 :(得分:0)

这种方法使用“桶”。下面的代码将时间戳向下舍入到最近的10分钟间隔:

CREATE TABLE #Test( ID INT, DT DATETIME, Username VARCHAR( 50 ), ReadID INT )
INSERT INTO #Test
VALUES(
1, '2016/06/08 15:49:10.000', 'user1', 5859 ),
( 2, '2016/06/08 15:48:39.000', 'user1', 5859 ),
( 3, '2016/06/08 15:47:53.000', 'user3', 5859 ),
( 4, '2016/06/08 15:35:58.000', 'user1', 5859 )

SELECT *
FROM
    ( SELECT *,
        -- Note integer division is used to round down to nearest 10 min interval
        DATEADD( MINUTE, DATEDIFF( MINUTE, 0, DT ) / 10 * 10, 0 ) AS TenMinuteIntervals,
        DENSE_RANK() OVER( PARTITION BY DATEADD( MINUTE, DATEDIFF( MINUTE, 0, DT ) / 10 * 10, 0 ) ORDER BY ID ) AS Duplicates
    FROM #Test ) AS Buckets
WHERE Duplicates = 1

输出:

 ID DT                  Username    ReadID  
 4  2016-06-08 15:35:58.000 user1   5859  
 1  2016-06-08 15:49:10.000 user1   5859 

要返回不同的读取,您需要将ReadID列添加到PARTION BY子句

DENSE_RANK() OVER( PARTITION BY ReadID, DATEADD( MINUTE, DATEDIFF( MINUTE, 0, DT ) / 10 * 10, 0 ) ORDER BY ID )

要返回每个ReadID的聚合结果,您需要添加GROUP BY

SELECT ReadID, COUNT( * ) AS Cnt
FROM
    ( SELECT *,
        DENSE_RANK() OVER( PARTITION BY ReadID, DATEADD( MINUTE, DATEDIFF( MINUTE, 0, DT ) / 10 * 10, 0 ) ORDER BY ID ) AS Duplicates
    FROM #Test ) AS Buckets
WHERE Duplicates = 1
GROUP BY ReadID

答案 1 :(得分:0)

尝试:

;WITH cte AS (
    SELECT *, ROW_NUMBER() 
        OVER (ORDER BY dte ASC) 
    AS rn 
    FROM #t1
) 

SELECT 
CASE 
    WHEN COUNT(id) > 0 
        THEN COUNT(id) 
    ELSE 
        1 
END AS cNt 
FROM #t1 
WHERE id IN (
    SELECT 
    id 
    FROM (
        SELECT 
            t1.id id1
            , t2.id id2 
        FROM cte t1 
            LEFT JOIN 
            cte t2 
                ON t1.rn = t2.rn+1 
        WHERE 
            DATEDIFF(n, t2.dte,t1.dte) >= 10
    ) cte_usage
    UNPIVOT (
        id 
        FOR ids 
        IN (
            id1
            , id2
        )) AS up
)