Как рассчитать среднее значение столбца, а затем включить его в запрос на выборку в Oracle? - PullRequest
6 голосов
/ 10 марта 2012

Мой стол -

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 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 ]

11 голосов
/ 10 марта 2012

Поскольку вы используете 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

Нет необходимости в подзапросах или GROUP BY.

8 голосов
/ 10 марта 2012

Ваша группа - это то, что агрегирует ваше среднее значение, и она группируется по всей таблице (я предполагаю, что вы сделали это, чтобы разрешить выбор для всего). Просто переместите свой 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;

Когда вы запускаете базовый оператор SELECT AVG(cost), он естественным образом группируется по указанному столбцу (в данном случае - к стоимости), поскольку именно это вы запрашиваете. Я бы посоветовал прочитать больше о GROUP BY и агрегатах , чтобы лучше понять концепцию. Это должно помочь вам больше, чем просто решение.

UPDATE:

Ответ, приведенный ниже, фактически основан на ответе Давида. Это делает использование аналитических функций. По сути, происходит то, что при каждом вызове 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 допускает переменные, вы также можете легко сделать ответ ниже. Я на самом деле предпочитаю это для будущей ремонтопригодности / удобочитаемости. Причина в том, что переменная с хорошим именем может быть очень наглядной для будущих читателей кода, в отличие от аналитической функции, которая требует немного больше работы для чтения (особенно если вы не понимаете функцию over).

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

Это переменные в SQL-сервере (вам придется адаптировать его для собственного экземпляра 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

2 голосов
/ 10 марта 2012

Самое простое изменение - изменить avg(cost) as Average на (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
;
0 голосов
/ 08 августа 2016
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
0 голосов
/ 10 марта 2012

Один из редких случаев применения 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
0 голосов
/ 10 марта 2012

попробуй

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;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...