views:

339

answers:

2

Hi, I need to calculate the backlog from a table: components(ProductId, ComponentId, Status, StatusDate) where ComponentId, Status and StatusDate are the primary key. ProductId is a foreign key. Example:

prod1, comp1, 01, 05/01/2009
prod1, comp1, 02, 05/01/2009
prod1, comp1, 03, 06/01/2009
prod1, comp1, 01, 07/01/2009
prod1, comp1, 02, 20/01/2009
prod2, comp2, 01, 22/01/2009
prod1, comp1, 02, 23/01/2009
prod1, comp1, 03, 31/01/2009

Basically what I am trying to calculate is the number of Components per week in status lower than 03. End user will introduce an interval date so I need to show all the weeks in the interval even if there is not backlog for a week. Expected result when end user introduces 01/01/2009-22/01/2009:

Week, Backlog
1,NULL/0
2,1
3,1
4,2

Explanation for Week 2: comp1 reach status 03 in the week but then goes back to status 01
Any help is more than welcome, thanks

A: 

This is a partial answer in that I do not see where week 3 (11-18 Jan 2009) is coming from in your example. It illustrates the use of a counter table to get a line for missing values.

SELECT Counter,WeekNo, CountofStatus FROM Counter LEFT JOIN
    (SELECT Format([StatusDate],"ww") AS WeekNo, COUNT(c.Status) AS CountOfStatus
    FROM components c
    WHERE c.StatusDate BETWEEN #1/1/2009# AND #1/22/2009#
    AND c.Status<3
    GROUP BY Format([StatusDate],"ww")) Comp
ON Val(Comp.Weekno)=Counter.Counter   
WHERE Counter.Counter>=Val(Format(#1/1/2009#,"ww"))
AND Counter.Counter<=Val(Format( #1/22/2009#,"ww"))
Remou
Thank you very much Remou, I will try right away. In the example, Week 3 has one component in status lower than 03 (comp1 is in status 01 from Week 2)
So the status is continuous and only marked at date changed? If so, my example does not suit.
Remou
Correct,I tried with a UDF: per each week check per each component that status of maximum statusDate. If status is < 3, I count. If not component found for the given week, I check the Status of the latest Statusdate component before the given week. But it take ages and Acces file grows like hell :(
Your example shows two components, do you have a set number of components and is it large?
Remou
Currently there are 1000 components and I think the number increases around 50 per month
A: 

I'm guessing a bit as to what you're trying to do, but here's my best guess:

First, you should have a calendar table in your database:

CREATE TABLE Calendar (
     calendar_date DATETIME NOT NULL,
     week_number INT NOT NULL,
     CONSTRAINT PK_Calendar PRIMARY KEY CLUSTERED (calendar_date)
)
GO

INSERT INTO Calendar (calendar_date, week_number) VALUES ('1/1/2009', 1)
INSERT INTO Calendar (calendar_date, week_number) VALUES ('2/1/2009', 2)
etc.

You can add additional columns to the table based on your business needs. For example, an "is_holiday" bit column to track whether or not your office is closed that day. This table makes so many different queries trivial.

Now for your problem:

SELECT
     CAL.week_number,
     COUNT(DISTINCT C.component_id)
FROM
     Calendar CAL
LEFT OUTER JOIN Components C ON
     C.status_date = CAL.calendar_date AND
     C.status IN ('01', '02')
WHERE
     CAL.calendar_date BETWEEN @start_date AND @end_date
GROUP BY
     CAL.week_number

I used the IN for the status since you're using strings, so "< '03'" might not always give you what you want. Is '1' less than '03' in your mind?

Also, if there is a time component on any of your dates the equality and BETWEEN checks might need to be tweaked.

EDIT: I just saw the comments on the other answer. If you are dealing with just status changes, then the following query should work, although there may be a more performant method:

SELECT
     CAL.week_number,
     COUNT(DISTINCT C.component_id)
FROM
     Calendar CAL
LEFT OUTER JOIN Components C ON
     C.status_date <= CAL.calendar_date AND
     C.status IN ('01', '02')
LEFT OUTER JOIN Components C2 ON
     C2.component_id = C.component_id AND
     C2.status_date > C.status_date AND
     C2.status_date <= CAL.calendar_date
WHERE
     CAL.calendar_date BETWEEN @start_date AND @end_date AND
     C2.component_id IS NULL
GROUP BY
     CAL.week_number

I'm not sure where the product fits in with all of this though.

Tom H.