2016-06-24 1 views
2

У меня есть таблица (назовем ее DiodeSales), которая сообщает мне общее количество продаж диодов, которые я сделал, сгруппированные по дате, цвет диода и страну. Это образец этой схемы:Как я могу рассчитать ежедневные снимки моих общих продаж на SQL?

 
Date      Color Country Sales 
June, 20 2016 00:00:00 Green US  1   
June, 20 2016 00:00:00 Red  Japan  1   
June, 20 2016 00:00:00 Red  US  1   
June, 21 2016 00:00:00 Red  US  1   
June, 22 2016 00:00:00 Green US  1   
June, 22 2016 00:00:00 Red  US  1   
June, 23 2016 00:00:00 Green US  1   
June, 23 2016 00:00:00 Red  Japan  1   
June, 23 2016 00:00:00 Red  US  1   
June, 24 2016 00:00:00 Green US  1   
June, 24 2016 00:00:00 Red  US  1    

Я хочу, чтобы иметь возможность иметь дополнительный столбец, который говорит мне, сколько диодов мы продали до этого момента. Так, например, используя приведенные выше данные, строка {June 23, Red, 1, US} будет иметь общую стоимость продаж 4, потому что в этот момент мы продали 4 красных диода в США.

Первоначально я думал, что общая сумма будет делать трюк. Так что я написал это: (sqlfiddle here)

SELECT 
    t1.Date, 
    t1.Color, 
    t1.Country, 
    t1.Sales, 
    SUM(t2.Sales) AS CumulativeSales 
FROM DiodeSales AS t1 
INNER JOIN DiodeSales AS t2 
ON t1.Date >= t2.Date 
    AND t1.Color = t2.Color 
    AND t1.Country = t2.Country 
GROUP BY 
    t1.Date, 
    t1.Color, 
    t1.Country 

Это дает мне накопленную сумму, как и ожидалось, но это не дает мне общий объем продаж для данного цвета в той или иной стране в определенный день. В частности, поскольку некоторые конкретные дни могут иметь 0 продаж в какой-либо стране, они не будут иметь кумулятивного значения, связанного с ним. Например, рассмотрим результаты предыдущей таблицы:

 
Date      Color Country Sales CumulativeSales 
June, 20 2016 00:00:00 Green US  1  1 
June, 20 2016 00:00:00 Red  Japan  1  1 
June, 20 2016 00:00:00 Red  US  1  1 
June, 21 2016 00:00:00 Red  US  1  2 
June, 22 2016 00:00:00 Green US  1  2 
June, 22 2016 00:00:00 Red  US  1  3 
June, 23 2016 00:00:00 Green US  1  3 
June, 23 2016 00:00:00 Red  Japan  1  2 
June, 23 2016 00:00:00 Red  US  1  4 
June, 24 2016 00:00:00 Green US  1  4 
June, 24 2016 00:00:00 Red  US  1  5 

Если бы я посмотреть на столбец, соответствующий Японии 24 июня, я не нашел бы ничего (потому что не было в Японии продажи в тот же день, так что не является японской строкой на тот день). Я не думаю, что есть способ сделать это в SQL, но можно ли заполнить эту итоговую таблицу значениями в дни, когда некоторые страны не имели продаж? Стартовая таблица всегда будет содержать по крайней мере одну колонку для каждого дня для определенной страны.

Я знаю, я мог бы просто написать простой

 
SELECT SUM(Sales) FROM DiodeSales 
WHERE Date <= @someDate AND Color = @someColor AND Country = @someCountry 

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

EDIT: Кто-то упомянул об этом как потенциальный дубликат Calculate a Running Total in SQL Server, но этот пост учитывает эффективность только при вычислении текущей суммы. У меня уже есть различные способы расчета этой суммы, но я ищу способ исправить проблему отсутствия комбинаций день/страна в течение дней, когда в этой стране не было продаж. Для приведенного выше примера, фиксированный запрос возвратит это:

 
Date      Color Country Sales CumulativeSales 
June, 20 2016 00:00:00 Green US  1  1 
June, 20 2016 00:00:00 Red  Japan  1  1 
June, 20 2016 00:00:00 Red  US  1  1 
June, 21 2016 00:00:00 Green US  0  1 
June, 21 2016 00:00:00 Red  Japan  0  1 
June, 21 2016 00:00:00 Red  US  1  2 
June, 22 2016 00:00:00 Green US  1  2 
June, 22 2016 00:00:00 Red  Japan  0  1 
June, 22 2016 00:00:00 Red  US  1  3 
June, 23 2016 00:00:00 Green US  1  3 
June, 23 2016 00:00:00 Red  Japan  1  2 
June, 23 2016 00:00:00 Red  US  1  4 
June, 24 2016 00:00:00 Green US  1  4 
June, 24 2016 00:00:00 Red  Japan  0  2 
June, 24 2016 00:00:00 Red  US  1  5 
+0

Добавлено SQL-сервер и SQL-сервер-2016 в тегах. –

+2

Возможный дубликат [Рассчитать общее количество в SQL Server] (http://stackoverflow.com/questions/860966/calculate-a-running-total-in-sql-server) –

+0

Вы помечаете свой вопрос SQL-Server- 2016, но SQLFiddle создается для MySQL. Какая из них истинна? –

ответ

3

Попробуйте это:

SELECT [Date], Color, Country, Sales, 
    SUM(Sales) OVER(PARTITION BY Color, Country ORDER BY [Date] rows unbounded preceding) as RunningTotal 
FROM YourTable 
ORDER BY [Date], Color 

Он производит вывод, как и ожидалось.

[EDIT]

Если вы ищете решение для отсутствующих дат, страны и цвета, попробуйте это (замените @tmp с именем вашей таблицы):

SELECT A.[Date], A.Color, A.Country, COALESCE(B.Sales, 0) AS Sales 
    , SUM(COALESCE(B.Sales, 0)) OVER(PARTITION BY A.Color, A.Country ORDER BY A.[Date] rows unbounded preceding) as RunningTotal 
FROM (
    SELECT [Date], Color, Country 
    FROM (SELECT DISTINCT [Date] FROM @tmp) AS q1 CROSS JOIN 
     (SELECT DISTINCT Color FROM @tmp) AS q2 CROSS JOIN 
     (SELECT DISTINCT Country FROM @tmp) AS q3 
    ) AS A 
LEFT JOIN @tmp AS B ON A.[Date] = B.[Date] AND A.Color= B.Color AND A.Country = B.Country 
ORDER BY A.[Date], A.Color 

Выше запроса производит:

Date Color  Country Sales RunningTotal 
2016-06-20 Green Japan 0  0 
2016-06-20 Green US  1  1 
2016-06-20 Red  Japan 1  1 
2016-06-20 Red  US  1  1 
2016-06-21 Green US  0  1 
2016-06-21 Green Japan 0  0 
2016-06-21 Red  US  1  2 
2016-06-21 Red  Japan 0  1 
2016-06-22 Green Japan 0  0 
2016-06-22 Green US  1  2 
2016-06-22 Red  Japan 0  1 
2016-06-22 Red  US  1  3 
2016-06-23 Green US  1  3 
2016-06-23 Green Japan 0  0 
2016-06-23 Red  US  1  4 
2016-06-23 Red  Japan 1  2 
2016-06-24 Green Japan 0  0 
2016-06-24 Green US  1  4 
2016-06-24 Red  Japan 0  2 
2016-06-24 Red  US  1  5 
+0

Это приводит к тому же результату, который я получаю с моим запросом, поэтому проблема наличия дней с отсутствующими странами по-прежнему существует. –

+0

Извините, добавьте '[Date]' после 'PARTITION BY ...' –

+0

@FedericoParedes, проверьте мой ответ сейчас. –

2

Я думаю, вы должны использовать левое соединение вместо внутреннего соединения

SELECT 
t.Date, 
t.Color, 
t.Country, 
t.CumulativeSales 
from DiodeSales t 
left join 
(SELECT 
t1.Date, 
t1.Color, 
t1.Country, 
t1.Sales, 
SUM(t2.Sales) AS CumulativeSales 
FROM DiodeSales AS t1 
    GROUP BY 
    t1.Date, 
    t1.Color, 
t1.Country) t2 
    on 
t.Date=t2.date 
and t.Color=t2.color 
and t.Country=t2.country 
+0

Зачем сильно открывать двери, если есть простой способ добиться этого? –

+0

Сэр Я пробовал на самом деле я новичок в sql-запросах. –

+0

Не будет ли это вести себя так же, как запрос INNER JOIN, поскольку мы присоединяемся к той же таблице? –

0

Попробуйте

Select distinct Date into SalesDate From DiodeSales 

    SELECT S.Date,t.Color,t.Country,t.CumulativeSales 
    from DiodeSales t left join 
    (SELECt t1.Date,t1.Color,t1.Country,t1.Sales, 
    SUM(t2.Sales) AS CumulativeSales FROM DiodeSales AS t1 
     GROUP BY 
     t1.Date, 
     t1.Color, 
    t1.Country) t2 on 
     S.Date=t2.date 
    and t.Color=t2.color 
     and t.Country=t2.country 
     join 
     SalesDate S 
     on t.date=S.date 
Смежные вопросы