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...
精彩评论