Как вычислить среднее значение столбца, а затем включить его в запрос select в oracle?

мой стол--

create table mobile
(
  id integer,
  m_name  varchar(20),
  cost integer
)

и значения --

insert into mobile values(10,'NOkia',100);
insert into mobile values(11,'Samsung',150);
insert into mobile values(12,'Sony',120);

Я знаю, как рассчитать среднее значение по стоимости столбца, мой код-

 select avg(cost) from mobile;

и в результате 123

но я хочу рассчитать среднее, а затем также показать разницу.Я смог это сделать, но я не могу добавить столбец avg в запрос select--

мой код ---

SELECT id, m_name as "Mobile Name", cost as Price,avg(cost) as Average,
cost-(select avg(cost) from mobile) as Difference FROM mobile
group by id,m_name,cost;

и выход --

id      Mobile Name   Price  Average  Difference 
10      Nokia         100    100      -23
11      Samsung       150    150       27
12      Sony          120    120      -3

Я хочу исправить эту среднюю колонку.. Я хочу этого - - -

id      Mobile Name  Price  Average  Difference 
10      Nokia       100     123     -23
11      Samsung     150     123      27
12      Sony        120     123      -3

пожалуйста, помогите...

6 ответов


ваша группа-это то, что агрегирует ваше среднее значение, и оно группируется по всей таблице (я предполагаю, что вы сделали это, чтобы разрешить выбор для всего), просто переместите свой avg в другой подзапрос, удалите всеобъемлющую группу, и это должно ее решить.

SELECT id, m_name AS "Mobile Name", cost AS Price,
    (SELECT AVG(cost) FROM mobile) AS Average,
    cost-(SELECT AVG(cost) FROM mobile) AS Difference 
FROM mobile;

при запуске basic SELECT AVG(cost) заявление это, естественно, группировка по указанному столбцу (стоимость в этом случае), поскольку это то, что вы запрашиваете. Я бы предложил прочитать больше на ГРУППЫ ПО и Сростки чтобы лучше понять концепцию. Это должно помочь вам более простое решение.

обновление:

ответ ниже на самом деле из ответа Дэвида. Он использует аналитические функции. В принципе, происходит то, что при каждом вызове AVG вы говорите движку, что использовать для функции (в этом случае ничего). Достойную запись по аналитическим функциям можно найти здесь и здесь и больше с google по этому вопросу.

SELECT id, m_name AS "Mobile Name" cost AS Price, AVG(cost) OVER( ) AS Average, 
    cost - AVG(cost) OVER ( ) AS Difference
    FROM mobile

однако, если ваш SQL engine допускает переменные, вы можете так же легко сделать следующий ответ. Я действительно предпочитаю это для будущей ремонтопригодности / читаемости. Причина в том, что переменная с хорошим именем может быть очень описательной для будущих читателей кода по сравнению с аналитической функцией, которая требует немного больше работы для чтения (особенно если вы не понимаете функцию over).

кроме того, это решение дублирует один и тот же запрос дважды, поэтому, возможно, стоит сохранить среднее значение в переменной SQL. Затем вы можете изменить свое утверждение, чтобы просто использовать это глобальное среднее

это переменные в SQL-Server (вам придется адаптировать его для собственного экземпляра SQL)

DECLARE @my_avg INT;
SELECT @my_avg = AVG(cost) FROM Mobile;

    SELECT id, m_name AS "Mobile Name", cost AS Price,
        @my_avg AS Average, cost-@my_avg AS Difference 
    FROM mobile;

это решение будет читать намного чище для будущих читателей вашего SQL тоже


поскольку вы используете Oracle, вы должны иметь возможность использовать AVG () в качестве аналитической (оконной) функции:

SELECT id, m_name AS "Mobile Name" cost AS Price, AVG(cost) OVER( ) AS Average
     , cost - AVG(cost) OVER ( ) AS Difference
  FROM mobile

Не нужны подзапросы или группы.


самое простое изменение-изменить avg(cost) as Average to (select avg(cost) from mobile) as Average. Это также означает, что вам не понадобится GROUP BY пункт больше (так как он не делает то, что вы на самом деле хотели):

SELECT id,
       m_name AS "Mobile Name",
       cost AS "Price",
       (SELECT AVG(cost) FROM mobile) AS "Average",
       cost - (SELECT AVG(cost) FROM mobile) AS "Difference"
  FROM mobile
;

попробовать

SELECT id, m_name as "Mobile Name", cost as Price,(select avg(cost) from mobile) as Average),
cost-(select avg(cost) from mobile) as Difference FROM mobile
group by id,m_name,cost;

если ваш запрос слишком дорог, таким образом, напишите мне рекомендацию, тогда я улучшу ее.


один из редких случаев CROSS JOIN применяется:

WITH avgcost as (select round(avg(cost)) as Average from mobile)
SELECT id, m_name as "Mobile Name", cost as Price, Average,
cost-Average as Difference
FROM mobile cross join avgcost

что приведет к:

ID  Mobile Name PRICE   AVERAGE DIFFERENCE
10  NOkia       100     123     -23
11  Samsung     150     123     27
12  Sony        120     123     -3

select pid, name, price as actualcost, 
       AVERAGE = (select AVG(price) from Part_Master), 
       price - (select AVG(price) as diff from Part_Master) AS COST_DIFF 
from   Part_Master