开发者

How to get data for last 4 weeks per individual product/entry date

I have a problem where I have 4 days as input, and I must get values for their last 4 weeks for each

This last 4 weeks does not mean the most 4 recent weeks for which I have the solution.

    SELECT prodno, 
           ardate8n, 
           selloff1 
    FROM   sales s 
           JOIN ( SELECT CAST(DATE_SUB('2011-02-27', INTERVAL 1 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-27' AS adt
 UNION ALL
 SELECT CAST(DATE_SUB('2011-02-27', INTERVAL 2 WEEK) AS DECIMAL(8,0)) AS 开发者_开发知识库wdt, '2011-02-27' AS adt
 UNION ALL
 SELECT CAST(DATE_SUB('2011-02-27', INTERVAL 3 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-27' AS adt
 UNION ALL
 SELECT CAST(DATE_SUB('2011-02-27', INTERVAL 4 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-27' AS adt

UNION ALL

 SELECT CAST(DATE_SUB('2011-02-26', INTERVAL 1 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-26' AS adt
 UNION ALL
 SELECT CAST(DATE_SUB('2011-02-26', INTERVAL 2 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-26' AS adt
 UNION ALL
 SELECT CAST(DATE_SUB('2011-02-26', INTERVAL 3 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-26' AS adt
 UNION ALL
 SELECT CAST(DATE_SUB('2011-02-26', INTERVAL 4 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-26' AS adt

UNION ALL

 SELECT CAST(DATE_SUB('2011-02-25', INTERVAL 1 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-25' AS adt
 UNION ALL
 SELECT CAST(DATE_SUB('2011-02-25', INTERVAL 2 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-25' AS adt
 UNION ALL
 SELECT CAST(DATE_SUB('2011-02-25', INTERVAL 3 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-25' AS adt
 UNION ALL
 SELECT CAST(DATE_SUB('2011-02-25', INTERVAL 4 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-25' AS adt

UNION ALL

 SELECT CAST(DATE_SUB('2011-02-24', INTERVAL 1 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-24' AS adt
 UNION ALL
 SELECT CAST(DATE_SUB('2011-02-24', INTERVAL 2 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-24' AS adt
 UNION ALL
 SELECT CAST(DATE_SUB('2011-02-24', INTERVAL 3 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-24' AS adt
 UNION ALL
 SELECT CAST(DATE_SUB('2011-02-24', INTERVAL 4 WEEK) AS DECIMAL(8,0)) AS wdt, '2011-02-24' AS adt) days 
             ON s.ardate8n = days.wdt 
    WHERE  custno = 38726 
           AND deptno = 0 
           AND Find_in_set(prodno, '0020,0064,0070,0073,0096') > 0 
    ORDER by prodno,adt,ardate8n;

As you see I have the most recent 4 weeks hardcoded. This only reads most recent 4 weeks per product/per entry date, and if one or more weeks are missing records I don't get 4 rows.

So I need to get this dynamically with some kind of limit involved in this. The sales.ardate8n gives if there is record for a given day.

This returns the following data

0006, '2011-03-03', 20110127, 0
0006, '2011-03-03', 20110203, 0
0006, '2011-03-03', 20110210, 0
0006, '2011-03-04', 20110128, 0
0006, '2011-03-04', 20110204, 0
0006, '2011-03-05', 20110129, 0
0006, '2011-03-05', 20110205, 0
0006, '2011-03-05', 20110212, 0
0006, '2011-03-05', 20110219, 0

As you see for entry date 2011-03-03 a product has only 3 rows for same weekday. and for entry date 2011-03-04 a product has only 2 rows for same weekday.


Although a comma-separated list is a convenient way of passing a set of values to the query, it is unfit in situations like this one, where it is required that every value requested should be present in the dataset. So instead of being used as a list, the values should be made a data column, a row set. That would make it possible to include all of them in the resulting set.

The above applies to the list of prodno values in your query, but same goes for dates.

Here's an example of how it would be possible to meet the requirements if the input data were made into datasets:

SELECT
  p.prodno,
  d.date,
  CAST(DATESUB(d.date, INTERVAL (w.weeksAgo) WEEK) AS DECIMAL(8, 0)) AS ardate8n,
  s.selloff1

FROM       (SELECT @date1 AS date
  UNION ALL SELECT @date2
  UNION ALL SELECT @date3
  UNION ALL SELECT @date4) d

CROSS JOIN (SELECT 1 AS weeksAgo
  UNION ALL SELECT 2
  UNION ALL SELECT 3
  UNION ALL SELECT 4) w

CROSS JOIN (SELECT '0020' AS prodno
  UNION ALL SELECT '0064'
  UNION ALL SELECT '0070'
  UNION ALL SELECT '0073'
  UNION ALL SELECT '0096') p

LEFT JOIN sales s
  ON s.ardate8n = CAST(DATESUB(d.date, INTERVAL (w.weeksAgo) WEEK) AS DECIMAL(8, 0))
 AND s.prodno   = p.prodno
 AND s.custno   = 38726 
 AND s.deptno   = 0


I would add a simple table containing all available dates from start year to end year- your range of dates in the sales table.

then I would join the tables by date.

In the where I'll put the given date as upper limit.

I'll order by date.

and then simply:

select top 4

the join and the select will be of course foreach of the given dates.

It will be much quicker and efficient...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜