Нулевой счет для несуществующей групповой категории - PullRequest
2 голосов
/ 26 февраля 2012

Мне нужно найти список трех продуктов и их количество, сгруппированных по дате, за последние пять дней.Для этого я использовал TSQL ниже.

SELECT CONVERT(VARCHAR(10),WM_data,103) as Date, 
       Product = CASE 
                   WHEN WM_Product = 1 THEN 'Product A' 
                   WHEN WM_Product = 2 THEN 'Product B' 
                   ELSE 'Product C' 
                 END, 
       WM_qtd as Quantity 
  FROM Tb_InfoProduct 
GROUP BY CONVERT(VARCHAR(10),WM_data,103), WM_Product
  HAVING CONVERT(VARCHAR(10),WM_data,103) > convert(VARCHAR(10),dateadd(dd, -5, getdate()),103) 
ORDER BY CONVERT(VARCHAR(10),WM_data,103), WM_Product

В результате я получаю:

Date          Product     Quantity
-------------------------------------------------
16/02/2012    Product A    132
16/02/2012    Product C     10
17/02/2012    Product A    163
17/02/2012    Product B     61
17/02/2012    Product C     58
18/02/2012    Product A      7
18/02/2012    Product B      2

Но мне нужно:

Date     Product     Quantity
-------------------------------------------------
16/02/2012   Product A   132
16/02/2012   Product B     0  -- This
16/02/2012   Product C    10
17/02/2012   Product A   163
17/02/2012   Product B    61
17/02/2012   Product C    58
18/02/2012   Product A     7
18/02/2012   Product B     2
18/02/2012   Product C     0   -- This

Как мне этого добиться

Ответы [ 2 ]

1 голос
/ 26 февраля 2012

Прежде всего, есть некоторые проблемы с вашим запросом:

  1. Ваше предложение SELECT содержит столбец, который не находится ни в GROUP BY, ни агрегирован - WM_qtd.Вы имели в виду SUM(WM_qtd), не так ли?

  2. В общем, даты, отформатированные с CONVERT(103), не могут быть ни осмысленно ни сопоставлены, ни отсортированы.Я бы посоветовал вам либо использовать другой формат (например, 112), либо вообще использовать другой метод удаления временной части и применить форматирование позже (только в предложении SELECT или, возможно, вообще не в SQL).).

  3. Вы фильтруете исходный набор данных с помощью предложения HAVING, что неэффективно, поскольку все данные должны быть извлечены, сгруппированы и только затем отфильтрованы.В этом конкретном случае было бы лучше отфильтровать данные с помощью предложения WHERE.

Теперь, что касается вашего вопроса ... Набор результатов, к которому вы стремитесь, в основном перекрестный.продукт всех соответствующих дат и всех соответствующих продуктов (упс, извините за каламбур).Он просто включает некоторую дополнительную информацию, такую ​​как Количество.

Таким образом, вам нужно получить два списка, даты и продукты, перекрестно соединить их, затем вы можете внешне объединить результирующий набор в Tb_InfoProduct и сгруппировать подата и продукт для получения чисел - так же, как вы уже делаете в своем запросе, только ссылки на столбцы даты и продукта, на которые будут ссылаться ваши предложения GROUP BY и SELECT, должны быть в соответствующих производных списках, а не вTb_InfoProduct таблица.

В целях моего ответа я предполагаю, что подмножество Tb_InfoProduct, которое вы запрашиваете, содержит все даты и все продукты, которые должны присутствовать в выходных данных, поэтому, чтобыПолучив два списка, я просто выбираю разные даты и разные продукты из подмножества Tb_InfoProduct.Вот примерное решение во всей его полноте:

SELECT
  Date = CONVERT(VARCHAR(10), d.Date, 103),
  Product = CASE p.WM_Product
    WHEN 1 THEN 'Product A'
    WHEN 2 THEN 'Product B'
    ELSE        'Product C'
  END,
  Quantity = SUM(WM_qtd)
FROM (
  SELECT DISTINCT Date = DATEADD(DAY, DATEDIFF(DAY, 0, WM_data), 0)
  FROM Tb_InfoProduct
  WHERE WM_data >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) - 4, 0)
) d
CROSS JOIN (
  SELECT DISTINCT WM_Product
  FROM Tb_InfoProduct
  WHERE WM_data >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) - 4, 0)
) p
LEFT JOIN (
  SELECT
    Date = DATEADD(DAY, DATEDIFF(DAY, 0, WM_data), 0),
    WM_Product
  FROM Tb_InfoProduct
  WHERE WM_data >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) - 4, 0)
) i ON d.Date = i.Date AND p.WM_Product = i.WM_Product
GROUP BY
  d.Date,
  p.WM_Product
ORDER BY
  d.Date,
  p.WM_Product

Если в запрашиваемом подмножестве могут отсутствовать некоторые даты и / или продукты, которые вы бы предпочли включить в выходные данные, вы должны составить список (ы) по-другому.Например, вы можете использовать справочную таблицу Products для списка продуктов, если она у вас есть, конечно.Что касается дат, вам может понадобиться сгенерировать список дат для данного диапазона, как предложено @OMG Ponies (и этот вопрос может помочь вам в этом: Получить список дат междудве даты с использованием функции ).

0 голосов
/ 27 марта 2012

при использовании sql 2008:

SELECT table1.date, table2.productid, isnull(table3.total,0) total FROM
--get the last 5 days
(
select distinct date from mytable1 where date > getdate() - 5
) table1
--get the 3 products
CROSS JOIN
(
select productid from product where productid in (1,2,3)
) table2
OUTER APPLY (SELECT SUM(1) Total from YourTable 
    where yourtable.date = table1.date 
    and yourtable.productid = table2.productid) Table3
...