web-dev-qa-db-fra.com

Comment calculer la moyenne d'une colonne puis l'inclure dans une requête select d'Oracle?

Ma table est--

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

et les valeurs sont -

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

Je sais comment calculer le coût moyen d'une colonne, mon code est--

 select avg(cost) from mobile;

et le résultat est 123

Mais je veux calculer la moyenne et montrer aussi la différence.J'ai pu le faire, mais je ne peux pas ajouter de colonne avg dans la requête select--

Mon code est ---

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;

et la sortie est -

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

ce que je veux, c'est corriger cette colonne moyenne. Je veux ceci ---

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

aidez s'il vous plaît ...

6
Ashish dmc4

Votre groupe par est ce qui agrège votre moyenne, et il regroupe par la table entière (je suppose que vous avez fait cela pour permettre la sélection pour tout). Il vous suffit de déplacer votre avg dans une autre sous-requête, de supprimer le groupe global par et cela devrait le résoudre. 

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;

Lorsque vous exécutez l'instruction SELECT AVG(cost) de base, elle est naturellement groupée par la colonne spécifiée (coût dans ce cas) car c'est ce que vous demandez. Je suggérerais de lire davantage sur GROUP BY et agrégats pour mieux comprendre le concept. Cela devrait vous aider plus qu'une simple solution.

UPDATE:

La réponse ci-dessous provient de la réponse de David. Il utilise les fonctions analytiques. En gros, à chaque appel AVG, vous indiquez au moteur ce qu'il doit utiliser pour la fonction (dans ce cas, rien). Vous pouvez trouver une description décente des fonctions d’analyse ici et ici et plus encore avec un google sur le sujet.

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

Toutefois, si votre moteur SQL autorise les variables, vous pouvez tout aussi bien répondre à la question ci-dessous. Je préfère en fait cela pour la maintenabilité/lisibilité future. La raison en est qu’une variable avec un bon nom peut être très descriptive pour les futurs lecteurs du code, par opposition à une fonction analytique qui nécessite un peu plus de travail à lire (surtout si vous ne comprenez pas la fonction over). 

De plus, cette solution duplique deux fois la même requête. Il peut donc être intéressant de stocker votre moyenne dans une variable SQL. Ensuite, vous pouvez changer votre déclaration pour utiliser simplement cette moyenne globale

Il s'agit de variables dans SQL-Server (vous devrez l'adapter à votre propre instance de 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;

Cette solution lira aussi beaucoup plus propre pour les futurs lecteurs de votre code SQL

8
Justin Pihony

Puisque vous utilisez Oracle, vous devriez pouvoir utiliser AVG () en tant que fonction analytique (fenêtre):

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

Pas besoin de sous-requêtes ou de GROUP BY.

11
David Faber

Le changement le plus simple consiste à remplacer avg(cost) as Average par (select avg(cost) from mobile) as Average. Cela signifie également que vous n’avez plus besoin de la clause GROUP BY (car elle ne fait pas ce que vous vouliez réellement):

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
;
2
ruakh
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
RAJU

essayer

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;

si votre requête est trop chère, envoyez-moi une recommandation, je l'améliorerai.

0
Angelo Fuchs

Un des rares cas où un CROSS JOIN est applicable:

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

Ce qui entraînera:

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