如何通过SQL查询在组中添加select?

时间:2016-10-14 17:24:01

标签: sql sql-server sql-server-2012

:我在SQL Server 2012中有一个数据库表mytable1。表定义是

Column_name Type        Length  Nullable
ts          datetime    8       no  
s_no        int         4       no  
calls       int         4       yes

DDL :并使用

创建
CREATE TABLE mytable1(
   ts DATETIME NOT NULL,
   s_no INT NOT NULL,
   calls  INT
);

填充数据

INSERT INTO mytable1 (ts, s_no, calls)
VALUES
('2016-10-14 10:04:01.000', 3, 56),
('2016-10-14 10:04:01.000', 4, 145),
('2016-10-14 10:09:00.000', 3, 143),
('2016-10-14 10:09:00.000', 4, 329),
('2016-10-14 10:14:01.000', 3, 0),
('2016-10-14 10:14:01.000', 4, 49),
('2016-10-14 10:19:00.000', 3, 6),
('2016-10-14 10:19:00.000', 4, 16),
('2016-10-14 10:24:01.000', 3, 22),
('2016-10-14 10:24:01.000', 4, 28),
('2016-10-14 10:29:00.000', 3, 4),
('2016-10-14 10:29:00.000', 4, 7),
('2016-10-14 10:34:00.000', 3, 14),
('2016-10-14 10:34:00.000', 4, 9),
('2016-10-14 10:38:59.000', 3, 39),
('2016-10-14 10:38:59.000', 4, 391),
('2016-10-14 10:44:01.000', 3, 3),
('2016-10-14 10:44:01.000', 4, 31),
('2016-10-14 10:49:01.000', 3, 116),
('2016-10-14 10:49:01.000', 4, 52),
('2016-10-14 10:54:00.000', 3, 75),
('2016-10-14 10:54:00.000', 4, 8),
('2016-10-14 10:59:00.000', 3, 16),
('2016-10-14 10:59:00.000', 4, 8),
('2016-10-14 11:04:01.000', 3, 23),
('2016-10-14 11:04:01.000', 4, 13);

我正在尝试将时间戳划分为30分钟的窗口,然后从每个30分钟的窗口中选择最大的时间戳。此外,我想为最高的30分钟时间戳选择所有不同的s_no值。

现有查询:我有一个执行此操作的查询

select m.s_no, m.bucket_window, max(m.ts) ts
from (
    select m.*, datepart(hour, m.ts)*2 + floor(datepart(minute, m.ts)/30) bucket_window
    from mytable1 m
    where m.ts >= DATEADD(dd, DATEDIFF(dd, 0, GETDATE()), 0)
) m
group by m.s_no, m.bucket_window;

结果:结果为

s_no    bucket_window   ts
3       20              2016-10-14 10:29:00.000
4       20              2016-10-14 10:29:00.000
3       21              2016-10-14 10:59:00.000
4       21              2016-10-14 10:59:00.000
3       22              2016-10-14 11:04:01.000
4       22              2016-10-14 11:04:01.000

现在我想改进此查询并在上面的结果中添加列调用。此列应具有 mytable1 表的调用列的值,其中 s_no ts 的组合来自上述结果匹配来自 mytable1 表的 s_no ts 的组合。

预期结果:我现在想要的结果是

s_no    bucket_window   ts                          calls
3       20              2016-10-14 10:29:00.000     4
4       20              2016-10-14 10:29:00.000     7
3       21              2016-10-14 10:59:00.000     16
4       21              2016-10-14 10:59:00.000     8
3       22              2016-10-14 11:04:01.000     23
4       22              2016-10-14 11:04:01.000     13

我尝试使用连接,但无法将查询与正确的语法结合在一起:

我尝试了什么:

select m.s_no, m.bucket_window, max(m.ts) ts, i.calls
from (
    select m.*, datepart(hour, m.ts)*2 + floor(datepart(minute, m.ts)/30) bucket_window
    from mytable1 m
    where m.ts >= DATEADD(dd, DATEDIFF(dd, 0, GETDATE()), 0)
) m
LEFT JOIN mytable1 i
ON max(m.ts) = i.ts--OR (m.ts) = i.ts
group by m.s_no, m.bucket_window, i.calls

请建议我如何修改此现有查询以获得预期结果。

由于此现有查询在生产中使用了很长时间,并在其他动态生成的查询中用作子查询,因此我不想完全更改它以获得预期结果。

3 个答案:

答案 0 :(得分:1)

试试这个

SELECT M1.*,
(SELECT calls From mytable1 M2 where M2.ts=M1.ts and M2.s_no=M1.s_no) as calls
FROM
(
    select m.s_no, m.bucket_window, max(m.ts) ts
    from (
        select m.*, datepart(hour, m.ts)*2 + floor(datepart(minute, m.ts)/30) bucket_window
        from mytable1 m
        where m.ts >= DATEADD(dd, DATEDIFF(dd, 0, GETDATE()), 0)
    ) m
    group by m.s_no, m.bucket_window
) M1

答案 1 :(得分:1)

好的,让我看看这是否可以帮到你:

select s_no, bucket_window, ts, c as calls from (
  select s_no, ts, bucket_window,
         max(ts) over (partition by s_no, bucket_window) maxts,     
         case 
           when ts=max(ts) over (partition by s_no, bucket_window) 
             then calls 
          end c 

          from (
                select m.*, 
                      datepart(hour, m.ts)*2 + floor(datepart(minute, m.ts)/30) bucket_window
                  from mytable1 m
                 where m.ts >= DATEADD(dd, DATEDIFF(dd, 0, GETDATE()), 0)
                     ) x  
          ) y    
   where  ts=maxts;

我从您的初始查询开始,但尝试不必再次加入mytable1。我不知道SQL Server语法,但我在rextester上测试了它,它说它应该工作。

这是我在rextester上准备的例子:我把所有三个可用解决方案放在一起,他们似乎都给出了你要求的答案。

由于我不了解SQL Server语法,因此我使用了我可能在Teradata或Oracle上使用的SQL标准分析函数来修改您的查询。

答案 2 :(得分:0)

使用top(1)with ties .. order by row_number()

select top(1) with ties m.s_no, datepart(hour, m.ts)*2 + floor(datepart(minute, m.ts)/30) bucket_window, ts, calls
from mytable1 m
where m.ts >= DATEADD(dd, DATEDIFF(dd, 0, GETDATE()), 0)
order by row_number() over (partition by m.s_no, datepart(hour, m.ts)*2 + floor(datepart(minute, m.ts)/30) 
           order by ts desc);