SQL Server-选择最接近30分钟间隔的行

时间:2020-07-22 15:18:44

标签: sql-server

我们正在使用SQL Server 2016:

这是我当前的表格:

countx  RunDateTime
104 7/15/20 0:05
104 7/15/20 0:10
102 7/15/20 0:15
102 7/15/20 0:20
100 7/15/20 0:25
100 7/15/20 0:30
102 7/15/20 0:35
99  7/15/20 0:40
97  7/15/20 0:46
99  7/15/20 0:56
93  7/15/20 1:01
93  7/15/20 1:10
93  7/15/20 1:16
91  7/15/20 1:31
89  7/15/20 1:39
87  7/15/20 1:57
88  7/15/20 2:05
80  7/15/20 2:11
81  7/15/20 2:20

我只想要以下结果

countx    RunDateTime
104   7/15/20 0:05
100   7/15/20 0:30
93    7/15/20 1:01
91    7/15/20 1:31
88    7/15/20 2:05

如何仅选择最接近最近的30分钟间隔的行?

我只希望最接近小时且最接近半小时的行

例如,我只希望最靠近的行

00:00和00:30

01:00和01:30

02:00和02:30

我能够选择最接近小时的行,但是我不知道如何获取最接近半小时的数据。这是我尝试过的。

SELECT  
       RunDateTime,
       COUNT(DISTINCT id) countxbyhour
FROM (SELECT 
            t.*, 
            MIN(RunDateTime) OVER(PARTITION BY CAST(RunDateTime AS DATE),
            DATEPART(HOUR,RunDateTime)) mintmstmp
      FROM table t) x
WHERE RunDateTime = mintmstmp
GROUP BY RunDateTime
ORDER BY RunDateTime

5 个答案:

答案 0 :(得分:0)

尝试一下...

IF OBJECT_ID('tempdb..#Table') IS NOT NULL DROP TABLE #Table

SELECT * INTO #Table FROM (VALUES
    (104, CAST('7/15/20 0:05' as datetime)),
    (104, '7/15/20 0:10'),
    (102, '7/15/20 0:15'),
    (102, '7/15/20 0:20'),
    (100, '7/15/20 0:25'),
    (100, '7/15/20 0:30'),
    (102, '7/15/20 0:35'),
    (99, '7/15/20 0:40'),
    (97, '7/15/20 0:46'),
    (99, '7/15/20 0:56'),
    (93, '7/15/20 1:01'),
    (93, '7/15/20 1:10'),
    (93, '7/15/20 1:16'),
    (91, '7/15/20 1:31'),
    (89, '7/15/20 1:39'),
    (87, '7/15/20 1:57'),
    (88, '7/15/20 2:05'),
    (80, '7/15/20 2:11'),
    (81, '7/15/20 2:20')
) S(countx, RunDateTime);

SELECT * FROM #Table;

WITH DataSource AS (
    SELECT
        *,
        CASE WHEN DATEPART(MINUTE, RunDateTime) >= 30 
            THEN (DATEPART(MINUTE, RunDateTime) - 30) / 30.0
            ELSE DATEPART(MINUTE, RunDateTime) / 30.0
        END FracHalfour
    FROM
        #Table
)
SELECT
    D.countx, D.RunDateTime
FROM
    DataSource D
    JOIN (
        SELECT
            countx,
            MIN(FracHalfour) FracHalfour
        FROM
            DataSource S
        GROUP BY
            countx
    ) S ON
        S.countx = D.countx AND
        S.FracHalfour = D.FracHalfour
ORDER BY
    countx DESC

答案 1 :(得分:0)

Jason击败了我,这是我的版本:

SELECT
    t.countx,
    t.RunDateTime
FROM
    test t
WHERE
    DATEPART(minute,t.RunDateTime) BETWEEN 0 AND 5
 OR (DATEPART(minute,t.RunDateTime) > 25 AND DATEPART(minute,t.RunDateTime) < 35)
 OR DATEPART(minute,t.RunDateTime) > 55

答案 2 :(得分:0)

如果最接近的意思是指半小时后的第一个时间值:

with data as (
    select *, row_number() over (
        partition by dateadd(minute, -datepart(minute, RunDateTime) % 30, RunDateTime)
        order by RunDateTime
    ) as rn
    from t
)
select * from data where rn = 1;

这基本上是通过简单的演绎来截断多余的分钟。我假设不涉及(毫秒)秒。

您还可以通过在“截断”操作之前加上15分钟并取距离的绝对值,将其“舍入”到最近的半小时:

with data as (
select *, row_number() over (
        partition by dateadd(minute, -datepart(minute, shiftedDt) % 30, shiftedDt)
        order by abs(datediff(minute, RunDateTime, dateadd(minute, -datepart(minute, RunDateTime) % 30, RunDateTime))), RunDateTime
    ) as rn
    from t cross apply ( values (dateadd(minute, 15, RunDateTime)) ) as s(shiftedDt)
)
select * from data where rn = 1;

关系在哪里发挥作用,需要较早的关系。另外,如果要在样本数据上使用此方法,它将返回一组不同的行。

答案 3 :(得分:0)

基于Jason的:

declare @t table(countx int, RunDateTime datetime);
insert into @t values
(104, '7/15/20 0:05'),
(104, '7/15/20 0:10'),
(102, '7/15/20 0:15'),
(102, '7/15/20 0:20'),
(100, '7/15/20 0:25'),
(100, '7/15/20 0:30'),
(102, '7/15/20 0:35'),
(99,  '7/15/20 0:40'),
(97,  '7/15/20 0:46'),
(99,  '7/15/20 0:56'),
(93,  '7/15/20 1:01'),
(93,  '7/15/20 1:10'),
(93,  '7/15/20 1:16'),
(91,  '7/15/20 1:31'),
(89,  '7/15/20 1:39'),
(87,  '7/15/20 1:57'),
(88,  '7/15/20 2:05'),
(80,  '7/15/20 2:11'),
(81,  '7/15/20 2:20');

WITH CTE AS
(--get data and dif
select *, ROW_NUMBER() OVER (PARTITION BY (countx) ORDER BY (CASE WHEN DATEPART(MINUTE, RunDateTime) >= 30 
            THEN (DATEPART(MINUTE, RunDateTime) - 30) / 30.0
            ELSE DATEPART(MINUTE, RunDateTime) / 30.0
        END)) as rowno
from @t
)
select *
from 
    CTE
where
    CTE.rowno = 1;

答案 4 :(得分:0)

我使用了Jasons代码中的一些想法来划分日期部分:

select 
RunDateTime,
count(distinct id) Countx
from (
        select t.*,
        min(RunDateTime) over(
        partition by cast(RunDateTime as date),( datepart(hour,RunDateTime)*100+CASE WHEN DATEPART(MINUTE, RunDateTime) >= 30 
    THEN 30
    ELSE 00 end )) mintmstmp
        from table t
     ) x
where RunDateTime=mintmstmp
group by RunDateTime
order by RunDateTime