2010-05-08 7 views
3

J'ai une table postgresql contenant les mouvements de différents éléments (modèles) entre les entrepôts.Calculer les différences entre les lignes lors du regroupement avec SQL

Par exemple, l'enregistrement suivant signifie que 5 unités de modèle 1 ont été envoyés sous forme entrepôt 1 à 2:

source target model units 
------ ------ ----- ----- 
    1  2  1  5 

Je suis en train de construire une requête SQL pour obtenir la différence entre les unités envoyées et reçues , regroupés par modèles. Encore une fois avec un exemple:

source target model units 
------ ------ ----- ----- 
    1  2  1  5 -- 5 sent from 1 to 2 
    1  2  2  1 
    2  1  1  2 -- 2 sent from 2 to 1 
    2  1  1  1 -- 1 more sent from 2 to 1 

Le résultat devrait être:

source target model diff 
------ ------ ----- ---- 
    1  2  1 2 -- 5 sent minus 3 received 
    1  2  2 1 

Je me demande si cela est possible avec une seule requête SQL.

Voici le script de création de la table et des données, tout le monde juste au cas où veut l'essayer:

CREATE TEMP TABLE movements 
(
    source INTEGER, 
    target INTEGER, 
    model INTEGER, 
    units INTEGER 
); 

insert into movements values (1,2,1,5); 
insert into movements values (1,2,2,1); 
insert into movements values (2,1,1,2); 
insert into movements values (2,1,1,1); 

Répondre

1

Est-ce que ce dont vous avez besoin? Je n'ai pas de base de données Oracle à tester donc j'espère que les règles sur les expressions de regroupement sont les mêmes que pour MS SQL Server

SELECT  
CASE WHEN source < target THEN source ELSE target END AS source, 
CASE WHEN source < target THEN target ELSE source END AS target, 
SUM(CASE WHEN source < target THEN units ELSE -units END) AS Diff, 
    model 
FROM movements 
GROUP BY 
CASE WHEN source < target THEN source ELSE target END, 
CASE WHEN source < target THEN target ELSE source END, 
    model 
4

Vous pouvez le faire avec deux sous-requêtes qui résument les mouvements dans chaque direction, puis l'union et la somme les résultats de ces deux sous-requêtes:

SELECT source, target, model, SUM(units) 
FROM (
    SELECT source, target, model, SUM(units) AS units 
    FROM movements 
    WHERE source < target 
    GROUP BY source, target, model 
    UNION ALL 
    SELECT target, source, model, SUM(-units) AS units 
    FROM movements 
    WHERE source > target 
    GROUP BY source, target, model 
) T1 
GROUP BY source, target, model 
+0

Bonne réponse! très clair! – msemelman

+0

Merci, laissez-moi essayer. Comment votre requête se compare-t-elle à la requête fournie par @Martin Smith, qui évite l'utilisation de "UNION ALL" (utilise des clauses CASE à la place)? –

+1

@Guido: Sa réponse scanne la table une seule fois, le mien la scanne deux fois. Combien de rangs avez-vous? La performance est-elle un problème? Je dirais que ma suggestion est plus claire/lisible, mais c'est ma propre opinion et est subjective. –

Questions connexes