【问题标题】:'group by' works on MySQL, but not Oracle'group by' 适用于 MySQL,但不适用于 Oracle
【发布时间】:2011-03-12 13:30:00
【问题描述】:

我有一个查询可以在 MySQL 上运行,但不能在 Oracle 上运行,我正在尝试转换。这是我的桌子:

unique_row_id  http_session_id  page_name   page_hit_timestamp
----------------------------------------------------------------
0              123456789        index.html  2010-01-20 15:00:00
1              123456789        info.html   2010-01-20 15:00:05
2              123456789        faq.html    2010-01-20 15:00:15
3              987654321        index.html  2010-01-20 16:00:00
4              987654321        faq.html    2010-01-20 16:00:05
5              987654321        info.html   2010-01-20 16:00:15
6              111111111        index.html  2010-01-20 16:01:00
7              111111111        faq.html    2010-01-20 16:01:05
8              111111111        info.html   2010-01-20 16:01:15

SQL 是

select http_session_id, unique_row_id, page_name, page_hit_timestamp 
from page_hits 
group by http_session_id;

在 MySQL 上,这将返回 3 行(每个唯一的 http_session_id 一行)。

在 Oracle 上,我收到“ORA-00979:不是 GROUP BY 表达式”错误。我也尝试过使用 distinct,但我无法让它工作。

为了清楚起见 - 我想要一个每个唯一 http_session_id 包含一行的 ResultSet。最好 unique_row_id 是最大值(例如 http_session_id==123456789 为 2),但这并不重要。

我即将将其分解为多个单独的 sql 语句(一个“选择不同的 http_session_id”,另一个迭代所有这些并选择 max(unique_row_id)。任何指针都将不胜感激 - 我会喜欢避免这种情况!

Rgds,凯文。

【问题讨论】:

    标签: mysql oracle plsql group-by ora-00979


    【解决方案1】:

    您遇到 ORA 错误的原因是因为 MySQL 支持非标准的 GROUP BY 子句,称其为“功能”。我是documented here

    标准 SQL GROUP BY 子句必须包含 SELECT 子句中指定的 ALL 列,这些列未包含在聚合函数(LIKE COUNT、MAX/MIN 等)中, 在 GROUP BY 子句中指定。

    如果您希望每个 http_session_id 值有一个唯一的行 - 请查看使用 ROW_NUMBER:

    SELECT x.*
      FROM (select http_session_id, unique_row_id, page_name, page_hit_timestamp,
                   ROW_NUMBER() OVER (PARTITION BY http_session_id 
                                          ORDER BY http_session_id) AS rank
              FROM page_hits) x
     WHERE x.rank = 1
    

    【讨论】:

    • 如果您想调整返回哪一行,可以将 ORDER BY 添加到 ROW_NUMBER。 MySQL 没有分析/窗口/排名功能,所以恐怕你不能将查询移植回 MySQL :(
    • 感谢您的全面回答 - 有助于了解 MySQL 的 Group By 是非标准的。顺便说一句 - 我在执行指定的 select 子句时遇到 ORA-30485 错误。
    • 我相信select是SQL Server语法。
    【解决方案2】:

    Oracle 中的另一个选项,如果您愿意的话:

    select DISTINCT
           FIRST_VALUE(unique_row_id)
           OVER (PARTITION BY http_session_id
                 ORDER BY unique_row_id DESC) unique_row_id,
           http_session_id,
           FIRST_VALUE(page_name)
           OVER (PARTITION BY http_session_id
                 ORDER BY unique_row_id DESC) page_name,
           FIRST_VALUE(page_hit_timestamp)
           OVER (PARTITION BY http_session_id
                 ORDER BY unique_row_id DESC) page_hit_timestamp
    from page_hits;
    

    这将获得一组不同的http_session_id,并且对于每个unique_row_idpage_namepage_hit_timestamp,从具有最大unique_row_id 的行中返回http_session_id,例如:

    unique_row_id  http_session_id  page_name   page_hit_timestamp
    ----------------------------------------------------------------
    2              123456789        faq.html    2010-01-20 15:00:15
    5              987654321        info.html   2010-01-20 16:00:15
    8              111111111        info.html   2010-01-20 16:01:15
    

    【讨论】:

      【解决方案3】:

      在标准 SQL 中,如果您有 GROUP BY 子句,则所有不属于该子句的列都必须在聚合中。在 MySQL 中,此规则在设计上有所放宽。

      例如,这在 MySQL 中是允许的,但在标准 SQL 中是不允许的:

      SELECT customer_id, country, SUM(amount) FROM records GROUP BY customer_id
      

      有一个警告:MySQL 假设您知道自己在做什么。如果同一客户在多个国家/地区有记录,则查询将简单地获取表中的第一个国家/地区,而忽略所有其他国家/地区。此外,由于行的顺序是未定义的,并且没有 ORDER BY,因此每次运行查询时可能会得到不同的结果。

      在标准 SQL 中,您有两种选择:

      SELECT customer_id, country, SUM(amount) FROM records GROUP BY customer_id, country
      

      SELECT customer_id, MIN(country), SUM(amount) FROM records GROUP BY customer_id
      

      【讨论】:

        【解决方案4】:

        这行得通吗:

        select max(unique_row_id), http_session_id
        from page_hits
        group by http_session_id
        

        顺便说一句;我的 sql 在结果集中为包含在结果集中但不在 group by 子句中的列返回什么? (page_name, page_hit_timestamp)

        【讨论】:

        • 嗨 - 是的,这可以解决问题。全文:select http_session_id, max(unique_row_id), max(page_name), max(page_hit_timestamp) from page_hits group by http_session_id;
        • 并回答您关于 MySQL 做什么的问题:- 它似乎从与第一个匹配的 http_session_id 关联的行返回列。我无法确定,因为我没有对其进行过多测试 - 它很可能在不同的条件下最后返回。
        • 是的,我将更改为 first(page_name)。
        【解决方案5】:

        我认为 GROUP BY 需要一个变量在 SQL 标准中的 WHERE 子句或聚合函数中使用过?

        尝试使用SELECT MAX(unique_row_id) GROUP BY http_session_id

        【讨论】:

          猜你喜欢
          • 2017-10-20
          • 1970-01-01
          • 2023-04-07
          • 2017-04-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-04-03
          相关资源
          最近更新 更多