2013-03-15 4 views
4

У меня есть набор данных на SQL сервере что-то вроде:разница Найти между двумя наборами записей

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 

Это означает, что клиент заказал 10 морковь и 8 лук (на один счет-фактуру), но на самом деле получил только 5 морковь и 4 луковицы. Если состояние равно нуль, то это первоначальное количество, если состояние С, то он корректируется количество

Мне нужно создать таблицу, как

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

, который показывает разницу между заказанным количеством и реальным количеством на каждый счете-фактуре , Я не знаю, как начать. Любая помощь глубоко признателен :)

+2

Пожалуйста, укажите RDBMS, что вы ориентируетесь, добавив соответствующий тег (Oracle, SQL Server, MySQL и т.д.). Могут быть ответы, которые используют преимущества языка или функций продукта, которые не поддерживаются повсеместно. Кроме того, пометив его конкретными СУБД, ваш вопрос может привлечь внимание от людей, более подходящих для ответа на него. – Taryn

+0

Итак, вы говорите, что поля кортежа 'ID_Invoice, Article, Status' образуют уникальный ключ и всегда есть строка с' Status = NULL', но строка 'Status = C' является необязательной? – biziclop

+0

не исчезают после размещения вопроса – giammin

ответ

1

Итак, прежде всего вы должны отделить реальное от упорядоченная, сделав 2 запросов, а затем вы должны оставили присоединиться заказы к фактическому .. что-то вроде этого

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) 

ПРИМЕЧАНИЕ! вам будет лучше, если у вас есть идентификатор для каждой статьи для использования в «левом соединении» вместо сравнения varchars.

Вот скрипку пример:http://sqlfiddle.com/#!2/16666/1

+1

На самом деле я использую идентификатор продукта как номер, просто подумал, что использование некоторых реальных имен в моем примере может облегчить анализ :) – RRM

2

Вы не указали, что RDBMS вы используете, но мой ответ ANSI-SQL совместим со стандартом :) Работает с каждым действительным РСУБД там.

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 

Этот ответ asuming, есть всегда запись с NULL состояния и соответствующей строки со статусом «C». Если это не так, то вам придется настроить его так:

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 ** Хорошо ** и ** Эффективно ** ответ.Я пытался ответить, когда увидел ваш ** ответ: P ** – Luv

+0

@Luv Спасибо :) – fancyPants

+0

> Этот ответ считается, всегда есть запись с статусом NULL и соответствующей строкой со статусом «C». Если это не так, вам придется настроить его следующим образом: – RRM

2

наименее ресурсоемким:

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) 

Посмотреть это работает здесь: http://sqlfiddle.com/#!4/f96adf/14

+0

Что такое СУБД? – fancyPants

+0

Нет, не будет. Например, 'DECODE()' MySQL делает нечто совершенно иное, чем то, что вы хотите сделать здесь. – fancyPants

+0

Я заметил (я так привык к Oracle), я обновил ответ для sqlserver – JWK

8

Вариант с простым выражением CASE без чрезмерного СОЕДИНЕНИЯ

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 

Результаты:

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

Демо на SQLFiddle

+0

+1 Больше всего ** Эффективный ** – Luv

+0

+1 Действительно элегантный – fancyPants

+0

@ Александр Федоренко: Просто для ** любопытства ** Можете ли вы объяснить [Почему ] (http://sqlfiddle.com/#!3/a7a77/1), т.е. если клиент ** получает больше, чем его количество. И, следовательно, как изменить свой ** запрос **. – Luv

Смежные вопросы