对不在有子句中的列进行分组

Posted

技术标签:

【中文标题】对不在有子句中的列进行分组【英文标题】:group by on a column not present in having clause 【发布时间】:2013-02-27 06:52:47 【问题描述】:

我有一个简单的 SQL 查询,其中包含 GROUP BY 、 HAVING 和 ORDER BY 子句。 HAVING 子句在 GROUP BY 中有一些我不想要的字段,这可能吗?因为我必须每小时对数据进行分组,并且在 HAVING 中有一个日期字段,所以分组无法正常工作。 代码是:

alter procedure [dbo].[sp_metadata_inflow]
@grp_name varchar(40) , @subgrp_name varchar(40)
as
begin
declare @i as int , @j as int,@k as int,@d as datetime , @m as datetime,@y as datetime;
set @d = datepart(day,'2012-12-13 10:54:55.000');
set @m = datepart(month,'2012-12-13 10:54:55.000');
set @y = datepart(YEAR,'2012-12-13 10:54:55.000');
set @i = 1;
set @j = @i - 1;
while (@i <=24)
begin
(SELECT  top 5 @i,
         ContactReason,
         @grp_name,
         @subgrp_name,
         COUNT(*)
 FROM   [ISRM].[dbo].[ITSM01ISRM]
 GROUP  BY ContactReason,datepart(day,CreatedDate),CurrentGroup,CurrentSubGroup
 HAVING (
         datepart(day,CreatedDate)= @d AND datepart(MONTH,CreatedDate)= @m
         AND datepart(year,CreatedDate) = @y AND datepart(hour,CreatedDate) <= @i
         AND datepart(hour,CreatedDate) >=@j
        )
        AND (CurrentGroup = @grp_name) AND (CurrentSubGroup = @subgrp_name)
);
set @i = @i + 1;
set @j =  @i -1;
end
end
go

【问题讨论】:

您能解释一下您的查询吗?我的意思是你想在实际中使用查询做什么? 所以,我想根据 Contact Reason(group by) 获取计数(*),对于一天中的每个小时......希望这是有道理的,我唯一的问题是我如何得到它无需在 group by 子句中编写 CreatedDate mysql(尽管不是标准的 SQL)中,HAVING 子句中的列可能不在 GROUP BY 中。见dev.mysql.com/doc/refman/4.1/en/group-by-hidden-columns.html 我可以使用 where 和 group by 吗?我需要使用 SQL 您使用的是哪个 DBMS?问这个是因为 MySQL 中没有 DATEPART 函数。 Check this post 【参考方案1】:

以下查询按小时对所有结果进行分组。为什么不希望在 GROUP BY 中有 CreatedDate?

SELECT
    ContactReason,
    CurrentGroup,
    CurrentSubGroup,
    dateadd(hour, datediff(hour, 0, CreatedDate), 0),
    COUNT(1) 
FROM [ISRM].[dbo].[ITSM01ISRM] 
WHERE
    (CurrentGroup = @grp_name) AND (CurrentSubGroup = @subgrp_name)
GROUP BY 
    ContactReason,
    dateadd(hour, datediff(hour, 0, CreatedDate), 0),
    CurrentGroup,
    CurrentSubGroup;

【讨论】:

【参考方案2】:

要真正回答您的问题,您似乎只想在 where 子句中使用这些条件。它看起来也很像 SQL-Server 语法,而不是标签所暗示的 MySQL。

同样值得注意的是,这是非常低效的:

    (datepart(day,CreatedDate)= @d 
AND datepart(MONTH,CreatedDate)= @m
AND datepart(year,CreatedDate) = @y 
AND datepart(hour,CreatedDate) <= @i 
AND datepart(hour,CreatedDate) >=@j ) 

在列上使用DATEPART 不仅会强制函数对每一行进行评估,还会消除列上任何索引的好处。最好写成Createddate &gt;= '20130227 00:00' AND CreatedDate &lt; '20130227 01:00'

此外,您在每个循环中执行 2 小时,这听起来不像预期的行为。

最后,我无法想象返回 24 个结果集是处理数据的最佳方式,如果您想要每小时计算一次,将小时作为列并执行一个查询并返回一个数据集是否没有意义?

例如

| ContactReason  | GroupName  | SubGroupName | 00:00 | 01:00 | 02:00 | 03:00 |.....| 23:00 |
|----------------+------------+--------------+-------+-------+-------+-------+.....+-------|
| Example Reason | Test Group | Sub Group    |   5   |   10  |    8  |    1  |.....|   14  |
| Another Reason | Test Group | Sub Group    |   3   |    1  |   13  |    8  |.....|   23  |

在这种情况下,您的查询可以写成

DECLARE @Date DATETIME = '20121213';

WITH Data AS
(       SELECT  ContactReason,
                GroupName = @grp_name,
                SubGroupName = @subgrp_name,
                CreatedHour = CAST(DATEADD(HOUR, DATEDIFF(HOUR, 0, Createddate), 0) AS TIME),
                [Value] = 1
        FROM    [ISRM].[dbo].[ITSM01ISRM] 
        WHERE   CurrentGroup = @grp_name
        AND     CurrentSubGroup = @subgrp_name
        AND     CreatedDate >= @Date
        AND     CreatedDate < DATEADD(DAY, 1, @Date)
)
SELECT  *
FROM    Data
        PIVOT
        (   COUNT(Value)
            FOR CreatedHour IN 
                (   [00:00], [01:00], [02:00], [03:00], [04:00], [05:00], 
                    [06:00], [07:00], [08:00], [09:00], [10:00], [11:00], 
                    [12:00], [13:00], [14:00], [15:00], [16:00], [17:00],
                    [18:00], [19:00], [20:00], [21:00], [22:00], [23:00]
        ) pvt;

【讨论】:

以上是关于对不在有子句中的列进行分组的主要内容,如果未能解决你的问题,请参考以下文章

MySQL TIMESTAMP 列 - 按天分组

选择不在 GROUP BY 子句中的列

在 SQL 中选择不在 Group By 中的列

sql 基础语句

将不在聚合函数中的列保留在分组语句中[重复]

使用 Python,如何按小时对 Dataframe 中的列进行分组?