Как выбрать и упорядочить по столбцам, не входящим в оператор Groupy By SQL - Oracle - PullRequest
2 голосов
/ 25 января 2011

У меня есть следующее утверждение:

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 ]

6 голосов
/ 25 января 2011

Не имеет смысла включать столбцы, которые не являются частью предложения 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

В качестве альтернативы, вам нужно сделать агрегат из столбцов Site, Desk

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 голос
/ 10 мая 2018

Отличный пост в блоге, подробно освещающий эту дилемму, находится здесь:

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;

Но name и publisher не добавляются из-за неоднозначности при агрегировании ...

Давайте проясним это:

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;
    
    1036 **
  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;
    

Надеюсь, это поможет.

1 голос
/ 25 января 2011

Я полагаю, что это

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;

... но трудно сказать без дополнительной информации и / или данных испытаний.

...