Hi,
I have the following table: log(productId, status, statusDate, department...)
, where productId, status and statusDate is the primary key.
Example:
id1 01 01/01/2009
id1 02 02/01/2009
id1 03 03/01/2009
id1 01 06/01/2009
id1 02 07/01/2009
id1 03 09/01/2009
id2 01 02/01/2009
id2 02 03/01/2009
id2 01 04/01/2009
id2 03 06/01/2009
id3 01 03/01/2009
id3 02 04/01/2009
I want to make a query that retrieves for each productId in status03, the time that has passed between the first time it reached status01 and status03.Result expected:
id1 2
id1 3
id2 4
Any idea? Thank you
views:
511answers:
3
A:
This would work in Sql Server. You'll likely have to translate parts of it for Access:
SELECT l3.productID, DATEDIFF(d,COALESCE(l1.statusDate,l3.statusDate),l3.statusDate) AS LeadTime
FROM log l3
LEFT JOIN log l1 ON l1.productID=l3.productID AND l1.Status='01'
AND l1.statusDate =
(
SELECT TOP 1 statusDate
FROM log lsub
WHERE lsub.Status='01' AND lsub.productID=l1.productID AND l1.statusDate<l3.StatusDate
ORDER BY statusDate DESC
)
WHERE l3.Status='03'
Joel Coehoorn
2009-03-12 15:27:18
How is that a helpful answer? If you don't have Access to test your SQL in it, it's just not useful to post it as an answer, in my opinion.
David-W-Fenton
2009-03-14 22:55:10
+2
A:
How about:
SELECT t.ID, t.Status, t.SDateTime,
(SELECT Top 1 SDateTime
FROM t t1 WHERE t1.Status = 1
AND t1.ID=t.ID
AND t1.SDateTime<t.SDateTime
AND t1.SDateTime>=
Nz((SELECT Top 1 SDateTime
FROM t t2
WHERE t2.Status=3
AND t2.ID=t.ID
AND t2.SDateTime<t.SDateTime),0)) AS DateStart,
[SDateTime]-[DateStart] AS Result
FROM t
WHERE t.Status=3
Remou
2009-03-12 16:12:07
+1
A:
I love stuff like this. Looks like it's more complicated than either of the other two answers so far have suggested. Here's a solution that will work. My apologies for the nasty formatting. Also, this will work in SQL Server, but I haven't used Access in forever, so you might need to adjust this a bit to work there. Or it may not work at all if Access doesn't support non-equijoins.
SELECT productId, MAX(tbl.TimeBetween)
FROM
(SELECT status_1.productId as productId, status_1.statusDate as status1Date, MIN(status_3.statusDate) as status3Date, DATEDIFF(m,status_1.statusDate, MIN(status_3.statusDate)) as TimeBetween
FROM
(SELECT productId, status, statusDate
FROM log
WHERE status = '01') status_1
INNER JOIN
(SELECT productId, status, statusDate
FROM log
WHERE status = '03') status_3
ON status_1.productId = status_3.productId AND status_3.statusDate > status_1.statusDate
GROUP BY status_1.productId, status_1.statusDate) tbl
GROUP BY productId, status3Date
ORDER BY productId, TimeBetween
- The innermost selects get the records for each status.
- Those are then joined to give the '03' status records that are greater than their corresponding '01' records (how often do you get to use a non-equijoin?)
- They are then filtered to give the MIN '03' record that is still after the corresponding '01' record.
- The outermost select enforces your 'first time it reached '01' status rule' since it may go to '01' status multiple times before reaching '03' status.
If someone else has a more elegant solution, I'd love to see it. I have had to write similar queries to this in the past, and I'd love to see a better solution to this type of problem.
Eric Petroelje
2009-03-12 17:03:26
I get a circular reference caused by 'TimeBetween' in my test of this solution.
Traingamer
2009-03-12 17:29:57
I didn't get that myself, but it could be an Access thing. Edited my answer to hopefully fix that.
Eric Petroelje
2009-03-12 17:34:06
Yup, you are right, it would be simpler. For some reason I was thinking Access couldn't do correlated subqueries, hence the over-complicatedness of mine.
Eric Petroelje
2009-03-12 18:01:17
Then maybe you should test your SQL in Access before posting it as an answer?
David-W-Fenton
2009-03-14 22:54:29