2013-03-15 13 views
4

J'ai un ensemble de données sur le serveur sql quelque chose comme:Trouver la différence entre deux ensembles d'enregistrements

ID ID_Invoice Article Quantity Status 
1 10   carrot 10  null 
2 10   carrot 5  C 
3 10   onion 8  null 
4 10   onion 4  C 
5 11   tomato 20  null 
6 11   tomato 18  C 
7 11   onion 2  null 
8 11   onion 1  C 

Cela signifie qu'un client a commandé 10 carottes et 8 oignons (sur une seule facture) mais effectivement reçu seulement 5 carottes et 4 oignons. Si l'état est nul, alors il est quantité d'origine, si l'état est C alors il est la quantité corrigée

Je dois générer une table comme

ID ID_Invoice Article Quantity 
1 10   carrot -5  
2 10   onion -4 
3 11   tomato -2 
4 11   onion -1 

qui montre la différence entre la quantité commandée et la quantité réelle sur chaque facture . Je n'ai aucune idée de comment commencer. Toute aide très apprécié :)

+2

S'il vous plaît préciser le SGBDR que vous ciblez en ajoutant la balise appropriée (Oracle, SQL Server, MySQL, etc.). Il peut y avoir des réponses qui tirent parti des fonctionnalités de langue ou de produit qui ne sont pas prises en charge universellement. En outre, en l'associant à un SGBDR spécifique, votre question peut susciter l'attention de personnes mieux à même d'y répondre. – Taryn

+0

Vous dites donc que les champs "ID_Invoice, Article, Status" du tuple forment une clé unique, et qu'il y a toujours une ligne avec "Status = NULL", mais la ligne "Status = C" est optionnelle? – biziclop

+0

ne pas disparaître après avoir posté une question – giammin

Répondre

1

Alors tout d'abord vous devez séparer le réel de l'ordre en faisant 2 requêtes et vous avez à gauche rejoindre les commandes à la réelle .. quelque chose comme ça

select 
    Recived.ID, 
    Recived.ID_Invoice, 
    Recived.Article, 
    Recived.Quantity - Ordered.Quantity as Quantity 
from 
    (select * from dataTable where Status is null) as Ordered 
    left join (select * from dataTable where Status = 'C') as Recived on (Ordered.ID_Invoice = Recived.ID_Invoice and Ordered.Article = Recived.Article) 

REMARQUE! vous serez mieux si vous avez un identifiant pour chaque article à utiliser dans la "jointure à gauche" au lieu de comparer varchars.

Voici un exemple violon:http://sqlfiddle.com/#!2/16666/1

+1

En fait, j'utilise l'ID de produit comme numéro, juste pensé que l'utilisation de vrais noms dans mon exemple pourrait faciliter l'analyse :) – RRM

2

Vous ne précisaient pas, que vous utilisez SGBDR, mais ma réponse est conforme à la norme ANSI-SQL :) Fonctionne avec tous les SGBDR valides là-bas.

SELECT 
yt1.ID_Invoice, 
yt1.Article, 
yt2.Quantity - yt1.Quantity AS Quantity 
FROM 
yourTable yt1 
INNER JOIN yourTable yt2 ON yt1.ID_Invoice = yt2.ID_Invoice 
          AND yt1.Article = yt2.Article 
          AND yt2.Status = 'C' 
WHERE 
yt1.Status IS NULL 

Cette réponse est Asuming, il y a toujours un enregistrement avec NULL Etat et la ligne correspondante avec le statut « C ». Si ce n'est pas le cas, vous auriez à régler comme ceci:

SELECT 
yt1.ID_Invoice, 
yt1.Article, 
CASE WHEN yt2.Quantity IS NULL THEN yt1.Quantity ELSE yt2.Quantity - yt1.Quantity END AS Quantity 
FROM 
yourTable yt1 
LEFT JOIN yourTable yt2 ON yt1.ID_Invoice = yt2.ID_Invoice 
          AND yt1.Article = yt2.Article 
          AND yt2.Status = 'C' 
WHERE 
yt1.Status IS NULL 
+0

+1 ** Bon ** et ** Effecient ** répondre.J'essayais de répondre quand j'ai vu votre ** réponse: P ** – Luv

+0

@Luv Merci :) – fancyPants

+0

> Cette réponse est supposée, il y a toujours un enregistrement avec Status NULL et la ligne correspondante avec le statut 'C'. Si ce n'est pas le cas, vous devrez l'ajuster comme ceci: – RRM

2

moins gourmand en ressources:

SELECT id_invoice 
, article 
, org_quantity 
, new_quantity 
, new_quantity - org_quantity diff 
FROM (SELECT id_invoice 
     , article 
     , max(CASE WHEN status IS NULL THEN quantity else null END) org_quantity 
     , max(CASE WHEN status = 'C' THEN quantity else null END) new_quantity 
     FROM orders 
     GROUP BY id_invoice 
     , article) 

voir travailler ici: http://sqlfiddle.com/#!4/f96adf/14

+0

À quoi sert RDBMS? – fancyPants

+0

Non, ce ne sera pas le cas. Le 'DECODE()' de MySQL par exemple fait quelque chose de complètement différent de ce que vous voulez faire ici. – fancyPants

+0

J'ai remarqué (je suis tellement habitué à Oracle), j'ai mis à jour la réponse pour sqlserver – JWK

8

Option avec expression simple CASE sans extension JOIN

SELECT ID_Invoice, Article, 
     SUM(CASE WHEN Status IS NULL 
    THEN -1 * Quantity ELSE Quantity END) AS Quantity 
FROM dbo.test38 
GROUP BY ID_Invoice, Article 

Résultat:

ID_Invoice Article Quantity 
10 carrot -5 
10 onion -4 
11 onion -1 
11 tomato -2 

Démo SQLFiddle

+0

+1 Plus ** Efficace ** – Luv

+0

+1 En effet élégant – fancyPants

+0

@Alexander Fedorenko: Juste pour ** curiosité ** pouvez-vous expliquer [Pourquoi ] (http://sqlfiddle.com/#!3/a7a77/1), c'est-à-dire si un client ** reçoit plus que sa quantité d'oredred **. Et donc comment modifier votre ** requête **. – Luv

Questions connexes