Table example:
PersonID BPDate sys dia
1 4/3/2009 130 70
1 5/24/2009 145 80
2 4/22/2009 136 90
2 6/10/2009 136 90
2 9/23/2009 136 90
Result example:
Person ID BPDate1 sys1 dia1 BPdate2 sys2 dia2 BPDate sys3
dia3
1 4/3/2009 130 70 5/24/2009 145 80
2 4/22/2009 136 90 6/10/2009 136 90
9/23/2009 136 90
Appreciate any help.
The easiest is the report. If you really want to do this in a query then
come back for instructions. Is your table really named "X" or do you want to
provide your actual table name?
Duane Hookom
MS Access MVP
"MS Access Scheduler Database"
<MSAccessSche...@discussions.microsoft.com> wrote in message
news:BAC02CF7-B127-4C9C...@microsoft.com...
SELECT X1.PersonID,
FIRST(X1.BPDate) AS BPDate1,FIRST( X1.sys) AS sys1, FIRST(X1.dia) As dia1,
FIRST(X2.BPDate) AS BPDate2, FIRST(X2.sys) AS sys2,FIRST(X2.dia) As dia2,
FIRST(X3.BPDate) AS BPDate3, FIRST(X3.sys) AS sys3, FIRST(X3.dia) As dia3
FROM (X AS X1 LEFT JOIN X As X2 ON X1.PersonID = X2.PersonID
AND X1.BPDate < X2.BPDate)
LEFT JOIN X As X3 ON X2.PersonID = X3.PersonID
AND X2.BPDate < X3.BPDate
GROUP BY X1.PersonID;
Ken Sheridan
Stafford, England
--
Message posted via AccessMonster.com
http://www.accessmonster.com/Uwe/Forums.aspx/access-queries/201001/1
The file also includes a single report solution in which the layout of the
report is amended in code at runtime to give the same effect. Using a
subreport is far easier, however. The code solution was only included to
demonstrate that in could be done that way in response to a reader's enquiry
for a magazine column written by a contact of mine.
Ken Sheridan
Stafford, England
--
Message posted via http://www.accessmonster.com
I proposed the following solution to an earlier posting by MS Access Scheduler
Database. I got no feedback on whether or not it did (or did not) work. The
original posting did say it wanted the top 3 out of 1 to many (implying more
than 3 was possible).
Step 1 as proposed by Jerry Whittle
SELECT X1.PersonID,
X1.BPDate,
X1.sys,
X1.dia
FROM X AS X1
WHERE X1.BPDate In
(SELECT TOP 3 X2.BPDate
FROM X AS X2
WHERE X2.PersonID=X1.PersonID
ORDER BY X2.BPDate DESC)
ORDER BY 1,2 DESC;
My addition to Jerry Whittle's post was:
The easiest way to handle this in a report would be to use a sub-report to
show the results. The main report would show the personId and not have any
other fields in it. Based on your table "X" the source for the main report
would be
SELECT Distinct PersonID
FROM X
The sub-report would use the query that Jerry Whittle has proposed (without
the final Order By clause. Set up the subreport as a multi column Across then
down (3 columns) report with the three fields BPDate, Sys, and Dia.
If you really, really need to do this in a query then Jerry Whittle's proposal
is a start on the queries I can envision to do this and the performance will
probably be terrible.
The next query will rank the three (or less) records returned by Jerry
Whittle's query (call it qJW) and then you will join this query (qRanked) to
itself three times and use the rank to return record 1, 2 and 3 for each PersonID.
SELECT A.PersonID, A.BPDate, A.Sys, A.Dia, Count(B.BPDate) as Rank
FROM qJW as A LEFT JOIN qJW as B
ON A.PersonID = B.PersonID
AND A.BPDate<B.BPDate
GROUP BY A.PersonID, A.BPDate, A.Sys, A.Dia
Now use that query (qRanked) in a query that looks like the following:
SELECT A.PersonID, A.BPDate, A.Sys, A.Dia
, B.BPDate, B.Sys, B.Dia
, C.BPDate, C.Sys, C.Dia
FROM (qRanked as A LEFT JOIN qRanked as B
On A.PersonID = B.PersonID
AND A.Rank = B.Rank-1)
LEFT JOIN qRanked as C
On A.PersonID = C.PersonID
AND A.Rank = C.Rank-2
I did forget to add one bit at the end to preclude multiple rows being
returned for each personID
WHERE A.Rank = 0
John Spencer
Access MVP 2002-2005, 2007-2010
The Hilltop Institute
University of Maryland Baltimore County
In reality, though, I can't envisage any circumstance when I'd ever do this,
as doing the same thing in a report/subreport is so simple, reliable and
would cater for any number of rows per personID. It can even be done in a
single report as my demo file shows, but again I can't conceive any reason
for doing it that way. The single report solution was devised solely in
response to a specific request for such a solution by a magazine reader,
merely to show that it was possible. Surprisingly the use of a subreport
seemed not to have occurred to the reader, nor to the author of the column,
who's a friend of mine.
Using subqueries I'd have thought the easiest way would be to create one
query for each of the three possible dates per personID, so for the first
date:
SELECT PersonID, X1.BPDate AS BPDate1, X1.sys AS sys1, X1.dia AS dia1
FROM X AS X1
WHERE BPDate =
(SELECT MIN(BPDate)
FROM X AS X2
WHERE X2.PersonID = X1.PersonID);
for the second:
SELECT PersonID, X1.BPDate AS BPDate2, X1.sys AS sys2, X1.dia AS dia2
FROM X AS X1
WHERE BPDate =
(SELECT MIN(BPDate)
FROM X AS X2
WHERE X2.PersonID = X1.PersonID
AND BPDate >
(SELECT MIN(BPDate)
FROM X AS X3
WHERE X3.PersonID = X2.PersonID
AND (SELECT COUNT(*)
FROM X AS X4
WHERE X4.PersonID = X3.PersonID)>=2));
and for the third:
SELECT PersonID, X1.BPDate AS BPDate3, X1.sys AS sys3, X1.dia AS dia3
FROM X AS X1
WHERE BPDate =
(SELECT MAX(BPDate)
FROM X AS X2
WHERE X2.PersonID = X1.PersonID
AND (SELECT COUNT(*)
FROM X AS X3
WHERE X3.PersonID = X2.PersonID)=3);
Its then just a case of outer joining them:
SELECT qryBP1.PersonID,
qryBP1.BPDate1, qryBP1.sys1, qryBP1.dia1,
qryBP2.BPDate2, qryBP2.sys2, qryBP2.dia2,
qryBP3.BPDate3, qryBP3.sys3, qryBP3.dia3
FROM (qryBP1 LEFT JOIN qryBP2 ON qryBP1.PersonID = qryBP2.PersonID)
LEFT JOIN qryBP3 ON qryBP2.PersonID = qryBP3.PersonID;
As with my original query this works with one, two or three rows per personID
in X, but no more, so both are reliant on the OP's statement that a patient
'may have up to 3 BP readings' being correct.
However its done, given that a report is so easy to constrict, a query
solution is reminiscent of Samuel Johnson's famous dictum that " it is like
a dog walking on its hinder legs. It is not done well; but you are surprised
to find it done at all".
Ken Sheridan
Stafford, England
>> Try the following. Don't be confused by the name of the FIRST operator; it
>> doesn't really do what it says on the tin, but in this case I think it should
>[quoted text clipped - 15 lines]
>> Ken Sheridan
>> Stafford, England
The reason is that the FIRST operator doesn't do what you might think and
return the first date in order. I realise now that this was what John was
getting at, but I wasn't using it to do that in fact. I'd tried to determine
the order of the dates returned by the join criteria, and use of the FIRST
operator was arbitrary.
It turns out however that in some situations, while maintaining the correct
date order across the columns, one of the dates and the sys and dia values
accompanying it are not returned at all. This doesn't surprise me greatly,
and in retrospect I should have expressed my doubts more in my first post.
As you see from my reply to John it can be done reliably by creating three
separate queries and then joining them, but with a large number of rows in
the table performance would not be good. Note also that it does rely on
there being no more than three rows per personID, which your first post said
was the case, but John has referred to another thread of yours which seemed
to throw some doubt on this.
I had hoped it could be done efficiently by a join, but if so I've been
unable to find a reliable way. Doing it in a report/subreport makes far more
sense and is very easy to do as the demo file to which I posted a link shows.
It also allows any number of rows per personID rather than a maximum of three.
Ken Sheridan
Stafford, England
--
Message posted via AccessMonster.com
http://www.accessmonster.com/Uwe/Forums.aspx/access-queries/201002/1