Могу ли я ограничить количество строк, которые будут использоваться для группы в выражении GROUP BY - PullRequest
1 голос
/ 18 сентября 2009

У меня странная проблема

У меня есть таблица со столбцами product_id, sales и day

Не все продукты продаются каждый день. Я хотел бы получить среднее количество продаж, которое было у каждого продукта за последние 10 дней, где оно имело продажи

Обычно я получаю среднее значение, как это

SELECT product_id, AVG(sales) 
FROM table 
GROUP BY product_id

Есть ли способ ограничить количество строк, которые нужно учитывать для каждого продукта?

Боюсь, это невозможно, но я хотел проверить, есть ли у кого-то идея

Обновление для уточнения:

Товар может быть продан в дни 1,3,5,10,15,17,20. Поскольку я не хочу получать среднее значение за все дни, а только среднее число дней, когда продукт действительно продавался, делая что-то вроде

SELECT product_id, AVG(sales) 
FROM table 
WHERE day > '01/01/2009' 
GROUP BY product_id

не будет работать

Ответы [ 4 ]

1 голос
/ 18 сентября 2009

Если вы хотите, чтобы последние 10 календарных дней с момента продажи товаров:

SELECT product_id, AVG(sales)
FROM table t
JOIN (
   SELECT product_id, MAX(sales_date) as max_sales_date
   FROM table
   GROUP BY product_id
) t_max ON t.product_id = t_max.product_id 
  AND  DATEDIFF(day, t.sales_date, t_max.max_sales_date) < 10
GROUP BY product_id;

Разница в датах зависит от сервера SQL, вам нужно заменить ее синтаксисом сервера для функций разницы дат.

Чтобы получить последние 10 дней, когда товар продавался:

SELECT product_id, AVG(sales)
FROM (
    SELECT product_id, sales, DENSE_RANK() OVER 
           (PARTITION BY product_id ORDER BY sales_date DESC) AS rn
    FROM Table
) As t_rn
WHERE rn <= 10
GROUP BY product_id;

Это означает, что sales_date - это дата, а не дата / время. Вам придется извлечь часть даты, если поле имеет дату и время.

И, наконец, бесплатная версия оконной функции:

SELECT product_id, AVG(sales)
FROM Table t
WHERE sales_date IN (
 SELECT TOP(10) sales_date 
 FROM Table s
 WHERE t.product_id = s.product_id
 ORDER BY sales_date DESC)
GROUP BY product_id;

Опять же, sales_date считается датой, а не датой и временем. Используйте другой ограничивающий синтаксис, если TOP не поддерживается вашим сервером.

0 голосов
/ 18 сентября 2009

Если это таблица транзакций продаж, то там не должно быть никаких строк для дней, в которые не было продаж. То есть, если ProductId 21 не имел продаж 1 июня, то в этой таблице не должно быть строк с productId = 21 и day = '1 June' ... Следовательно, вам не нужно ничего фильтровать - не должно быть ничего для отфильтровать

Select ProductId, Avg(Sales) AvgSales
From Table 
Group By ProductId

должно работать нормально. Так что, если это не так, то вы не объяснили проблему полностью или точно.

Кроме того, в своем вопросе вы указываете Avg (Sales) в примере SQL-запроса, но затем в тексте упоминаете «среднее количество продаж каждого продукта ...». Вы хотите среднюю сумму продаж или среднее количество торговых сделок? И хотите ли вы, чтобы это среднее значение было получено по одному продукту (то есть по одному выходному значению для каждого продукта) или среднее значение по продукту в день?

Если вы хотите получить средние показатели по одному продукту, просто по продажам за десять дней до этого? или за десять дней до даты последней продажи каждого товара? Если последнее, то

Select ProductId, Avg(Sales) AvgSales
From Table T
Where day > (Select Max(Day) - 10
             From Table
             Where ProductId = T.ProductID)
Group By ProductId

Если вы хотите получить среднее по одному продукту, то только для тех продаж за десять дней с продажами до даты последней продажи каждого продукта, тогда

Select ProductId, Avg(Sales) AvgSales
From Table T
Where (Select Count(Distinct day) From Table
       Where ProductId = T.ProductID
          And Day > T.Day) <= 10
Group By ProductId
0 голосов
/ 18 сентября 2009

Я не уверен, правильно ли я понял, но если вы хотите получить среднее значение продаж за последние 10 дней для ваших продуктов, вы можете сделать следующее:

SELECT Product_Id,Sum(Sales)/Count(*) FROM (SELECT ProductId,Sales FROM Table WHERE SaleDAte>=@Date) table GROUP BY Product_id HAVING Count(*)>0

ИЛИ Вы можете использовать функцию агрегирования AVG, которая проще:

SELECT Product_Id,AVG(Sales) FROM (SELECT ProductId,Sales FROM Table WHERE SaleDAte>=@Date) table GROUP BY Product_id

Обновлено

Теперь я понял, что вы имели в виду. Насколько я знаю, это невозможно сделать одним запросом. Это было бы возможно, если бы мы могли сделать что-то подобное (база данных Northwind):

select a.CustomerId,count(a.OrderId) 
from Orders a INNER JOIN(SELECT CustomerId,OrderDate FROM Orders Order By OrderDate) AS b ON a.CustomerId=b.CustomerId GROUP BY a.CustomerId Having count(a.OrderId)<10

но вы не можете использовать order by в подзапросах, если вы не используете TOP, который не подходит для этого случая. Но, возможно, вы можете сделать это следующим образом:

SELECT PorductId,Sales INTO #temp FROM table Order By Day

    select a.ProductId,Sum(a.Sales) /Count(a.Sales)
    from table a INNER JOIN #temp AS b ON a.ProductId=b.ProductId GROUP BY a.ProductId Having count(a.Sales)<=10
0 голосов
/ 18 сентября 2009

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

SELECT t1.product_id, SUM(t1.sales) / COUNT(t1.*) 
FROM table t1
   INNER JOIN (
               SELECT TOP 10 day, Product_ID
               FROM table t2
               WHERE (t2.product_ID=t1.Product_ID)
               ORDER BY DAY DESC 
               ) 
   ON (t2.day=t1.day) 

GROUP BY t1.product_id

Кстати: в этом подходе используется коррелированный подзапрос , который может быть не очень производительным, но теоретически должен работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...