如何选择和排序不在Group By SQL语句中的列 - Oracle

时间:2011-01-24 21:00:03

标签: sql oracle group-by sql-order-by

我有以下声明:

SELECT  
    IMPORTID,Region,RefObligor,SUM(NOTIONAL) AS SUM_NOTIONAL
From 
    Positions
Where
    ID = :importID
GROUP BY 
    IMPORTID, Region,RefObligor
Order BY 
    IMPORTID, Region,RefObligor

Positions中存在一些额外的列,我想作为“显示数据”的输出,但我不希望在group by语句中。

这些是Site, Desk

最终输出将包含以下列:

IMPORTID,Region,Site,Desk,RefObligor,SUM(NOTIONAL) AS SUM_NOTIONAL

理想情况下,我希望数据排序如下:

Order BY 
    IMPORTID,Region,Site,Desk,RefObligor

如何实现这一目标?

3 个答案:

答案 0 :(得分:6)

包含不属于GROUP BY子句的列是没有意义的。考虑一下SELECT子句中是否有MIN(X),MAX(Y),其他列(未分组)应该来自哪一行?

如果您的Oracle版本足够新,您可以使用SUM - OVER()来显示针对每个数据行的SUM(分组)。

SELECT  
    IMPORTID,Site,Desk,Region,RefObligor,
    SUM(NOTIONAL) OVER(PARTITION BY IMPORTID, Region,RefObligor) AS SUM_NOTIONAL
From 
    Positions
Where
    ID = :importID
Order BY 
    IMPORTID,Region,Site,Desk,RefObligor

或者,您需要从SiteDesk列中进行汇总

SELECT  
    IMPORTID,Region,Min(Site) Site, Min(Desk) Desk,RefObligor,SUM(NOTIONAL) AS SUM_NOTIONAL
From 
    Positions
Where
    ID = :importID
GROUP BY 
    IMPORTID, Region,RefObligor
Order BY 
    IMPORTID, Region,Min(Site),Min(Desk),RefObligor

答案 1 :(得分:1)

我相信这是

select
  IMPORTID,
  Region,
  Site,
  Desk,
  RefObligor,
  Sum(Sum(Notional)) over (partition by IMPORTID, Region, RefObligor) 
from
  Positions
group by
  IMPORTID, Region, Site, Desk, RefObligor
order by
  IMPORTID, Region, RefObligor, Site, Desk;

......但如果没有进一步的信息和/或测试数据,很难说清楚。

答案 2 :(得分:1)

一篇很好的博客文章详细介绍了这个困境:

http://bernardoamc.github.io/sql/2015/05/04/group-by-non-aggregate-columns/

以下是它的一些片段:

假设:

CREATE TABLE games (
  game_id serial PRIMARY KEY,
  name VARCHAR,
  price BIGINT,
  released_at DATE,
  publisher TEXT
);

INSERT INTO games (name, price, released_at, publisher) VALUES
  ('Metal Slug Defense', 30, '2015-05-01', 'SNK Playmore'),
  ('Project Druid', 20, '2015-05-01', 'shortcircuit'),
  ('Chroma Squad', 40, '2015-04-30', 'Behold Studios'),
  ('Soul Locus', 30, '2015-04-30', 'Fat Loot Games'),
  ('Subterrain', 40, '2015-04-30', 'Pixellore');

SELECT * FROM games;

 game_id |        name        | price | released_at |   publisher
---------+--------------------+-------+-------------+----------------
       1 | Metal Slug Defense |    30 | 2015-05-01  | SNK Playmore
       2 | Project Druid      |    20 | 2015-05-01  | shortcircuit
       3 | Chroma Squad       |    40 | 2015-04-30  | Behold Studios
       4 | Soul Locus         |    30 | 2015-04-30  | Fat Loot Games
       5 | Subterrain         |    40 | 2015-04-30  | Pixellore
(5 rows)

试图得到这样的东西:

SELECT released_at, name, publisher, MAX(price) as most_expensive
FROM games
GROUP BY released_at;

但由于汇总时含糊不清,因此未添加namepublisher ...

  

让我们说清楚:

Selecting the MAX(price) does not select the entire row.
     

数据库无法知道,何时无法给出正确答案   给定查询的时间应该给我们一个错误,那就是它   确实!

     

好的......好的......这不是那么简单,我们能做些什么?

  1. 使用inner join获取其他列

    SELECT g1.name, g1.publisher, g1.price, g1.released_at
    FROM games AS g1
    INNER JOIN (
      SELECT released_at, MAX(price) as price
      FROM games
      GROUP BY released_at
    ) AS g2
    ON g2.released_at = g1.released_at AND g2.price = g1.price;
    
  2. 或者使用left outer join获取其他列,然后按重复列的NULL进行过滤...

    SELECT g1.name, g1.publisher, g1.price, g2.price, g1.released_at
    FROM games AS g1
    LEFT OUTER JOIN games AS g2
    ON g1.released_at = g2.released_at AND g1.price < g2.price
    WHERE g2.price IS NULL;
    
  3. 希望有所帮助。