如何使用INNER JOIN进行GROUP BY

时间:2019-07-07 19:27:57

标签: sql sql-server

我对GROUP BY和INNER JOIN有一个小问题。我尝试将时间花在按用户分组的事件上,以查看抽动用户的效率。

此刻,我只收到错误消息

  

'列'XXX'在选择列表中无效,因为它既不包含在聚合函数中也不包含在GROUP BY子句中

我了解SELECT语句中的所有字段在GROUP BY中都是必需的,但是如果我对所有这些字段进行分组,则不会收到我想要的内容。

我认为我的问题是因为我不正确地理解GROUP BY和INNER JOIN,所以我试图学习很多网站,但至少在此刻我看不到错误。

这是我的代码:

SELECT
  id_incident_project AS ID,
  i.title AS title,
  companyname as social_name,
  username as tech_name,
  ia.DESCRIPTION_TEXT as description,
  CONVERT(varchar, ia.ACTIONDATE, 101) as action_date,
  CAST(TIME as INT) as acting_time,
  CAST(actions_time as INT) AS total_time
FROM
  incident i
  INNER JOIN incident_0001 i1 ON i1.ID_INCIDENT = i.ID_INCIDENT
  INNER JOIN incident_action ia ON ia.ID_INCIDENT = i.ID_INCIDENT
  INNER JOIN agent a ON a.ID_AGENT = ia.ID_AGENT
  INNER JOIN username u on u.ID_USERNAME = a.ID_USERNAME
WHERE
  ia.ACTIONDATE BETWEEN '## START DATE (YYYYMMDD)##' AND '## END DATE (YYYYMMDD)##'
GROUP BY username

1 个答案:

答案 0 :(得分:1)

SELECT子句中未分组的所有列都必须经过聚合函数。要获取某物,您可以将其通过MAX

SELECT
    MAX(id_incident_project) AS ID,
    MAX(i.title) AS title,
    MAX(companyname) as social_name,
    username as tech_name,
    MAX(ia.DESCRIPTION_TEXT) as description,
    MAX(CONVERT(varchar, ia.ACTIONDATE, 101)) as action_date,
    MAX(CAST(TIME as INT)) as acting_time,
    MAX(CAST(actions_time as INT)) AS total_time
FROM
    incident i
    INNER JOIN incident_0001 i1 ON i1.ID_INCIDENT = i.ID_INCIDENT
    INNER JOIN incident_action ia ON ia.ID_INCIDENT = i.ID_INCIDENT
    INNER JOIN agent a ON a.ID_AGENT = ia.ID_AGENT
    INNER JOIN username u on u.ID_USERNAME = a.ID_USERNAME
WHERE
    ia.ACTIONDATE BETWEEN '## START DATE (YYYYMMDD)##' AND '## END DATE (YYYYMMDD)##'
GROUP BY username

但是,在所有联接完成之后,当同一username有多个行时,此方法将冒着输出来自不同源行的值的风险。例如,如果用户名“ JohnSmith”发生(说)两次事件,一次事件发生在2019年1月1日,标题为“ Zombie Sighting”,第二次事件发生在2019-03-31,其标题为“ Aitch Dropping”,则“ “最高”标题将是“僵尸瞄准”,最晚日期是2019-03-31,因此针对不同事件。

为避免这种情况,您可以将GROUP BY替换为username上的分区,对事件进行排序,并以一致的方式为每个username选择一个事件:

SELECT
    ID, title, social_name, tech_name, description,
    action_date, acting_time, total_time
FROM (
    SELECT
        id_incident_project) AS ID,
        i.title AS title,
        companyname as social_name,
        username as tech_name,
        ia.DESCRIPTION_TEXT) as description,
        CONVERT(varchar, ia.ACTIONDATE, 101) as action_date,
        CAST(TIME as INT) as acting_time,
        CAST(actions_time as INT) AS total_time,
        ROW_NUMBER () OVER (
            PARTITION BY username
            ORDER BY
                ia.ACTIONDATE DESC,   -- pick out latest
                i1.ID_INCIDENT DESC   -- tie breaker
        ) AS OrderNum
    FROM
        incident i
        INNER JOIN incident_0001 i1 ON i1.ID_INCIDENT = i.ID_INCIDENT
        INNER JOIN incident_action ia ON ia.ID_INCIDENT = i.ID_INCIDENT
        INNER JOIN agent a ON a.ID_AGENT = ia.ID_AGENT
        INNER JOIN username u on u.ID_USERNAME = a.ID_USERNAME
    WHERE
        ia.ACTIONDATE BETWEEN '## START DATE (YYYYMMDD)##' AND '## END DATE (YYYYMMDD)##'
) t
WHERE t.OrderNum = 1