I need to combine multiple records into one row with multiple columns for those records. Very similar to a crosstab query, but one that shows all the records, not a summary of them.
For example, if the table is like this: - Name Month Score
-
John Jan 92
-
John Jan 90
-
John Feb 97
-
John Feb 91
I want a query that gives these results like this: - Month Name Score1 Score2
-
Jan John 92 90
-
Feb John 97 91
Crosstab queries are set for summarizing data, but I don't want that--I just want ALL the scores laid out in a row for each person for each month.
I'm using Access 2007 and in this case, VBA is not an option.
Any help would be much appreciated.
EDIT: See complete solution down below.
So ignore the fix from the previous post. Try adding the following to the end of line 9 of your last code: 27 15666
Can there be more than two scores per person per month? There is a SQL solution for that, but the more scores, the harder it is to code.
It would be a maximum of 4 scores.
Just an FYI, it is not a good idea to use Name or Month as field names as those are reserved words in Access. Access does permit you to use them, but it can sometimes cause problems.
Anyway, we first need to have an id field in your table. An autonumber field would be perfect for this. Then we need to create a querydef that puts a number beside each record to tell us if it is score 1, 2, 3 or 4. I'll assume a table name of tblScores. - SELECT ID
-
, [Name]
-
, [Month]
-
, Score
-
, DCount("*"
-
, "tblScores"
-
, "[Name] = '" & [Name] &
-
"' And [Month] = '" & [Month] &
-
"' And ID <= " & ID)
-
As ScoreNum
-
FROM tblScores
This should produce the results - ID Name Month Score ScoreNum
-
1 John Jan 92 1
-
2 John Jan 90 2
-
3 John Feb 97 1
-
4 John Feb 91 2
Save this query as qryScores. Now the query that gets the results that you want will have several subqueries to get the score numbers based on the ScoreNum field. - SELECT MQ.ID
-
, MQ.[Name]
-
, MQ.[Month]
-
, S1.Score As Score1
-
, S2.Score As Score2
-
, S3.Score As Score3
-
, S4.Score As Score4
-
FROM qryScores As MQ
-
LEFT JOIN (SELECT ID, Score FROM qryScores WHERE ScoreNum = 1) As S1 ON MQ.ID = S1.ID
-
LEFT JOIN (SELECT ID, Score FROM qryScores WHERE ScoreNum = 2) As S2 ON MQ.ID = S2.ID
-
LEFT JOIN (SELECT ID, Score FROM qryScores WHERE ScoreNum = 3) As S3 ON MQ.ID = S3.ID
-
LEFT JOIN (SELECT ID, Score FROM qryScores WHERE ScoreNum = 4) As S4 ON MQ.ID = S4.ID
Nice Work! That is probably preferable to a Crosstab as you will have a predefined amount of columns.
But if you wanted to, since you already did the hard work of creating a RowNumber type column, you could use a Crosstab ;) - TRANSFORM First(qryScores.[Month]) AS Scores
-
SELECT qryScores.[Name], First(qryScores.[Month]) AS ReportMonth
-
FROM qryScores
-
GROUP BY qryScores.[Name], qryScores.[Month]
-
PIVOT qryScores.[ScoreNum]
Thanks, Seth.
I know about reserved names and ID fields. It was just a simple example to illustrate what I was after.
I actually tried this method with the DCount function before, but it ran extremely slow due to the aggregate function. But I see a few differences in your function's criteria that I'll try out.
I'll test and post results.
Thanks!
The only way that you can speed up the query is to reduce the number of records that it has to run the aggregate function on.
NeoPa 32,462
Expert Mod 16PB
Actually Seth, you could link in the data as a separate data source rather than use a Domain Aggregate function call. The latter are notoriously inefficient and should be avoided where possible within SQL.
As J Forbes illustrates this can still be done using a cross-tab. I would expect that to work more efficiently as you're letting the SQL engine to the hard work - which is what it's designed for.
NeoPa, could you please clarify or give an example of linking in the data as a separate data source?
Thanks.
Seth, the performance is much better on the DCount function using the method in your example, thank you.
But I keep getting a "syntax error (missing operator)" on the second query example you gave with the subqueries. The error is in the section with the LEFT JOINS.
Any ideas?
Try this - SELECT MQ.ID
-
, MQ.[Name]
-
, MQ.[Month]
-
, S1.Score As Score1
-
, S2.Score As Score2
-
, S3.Score As Score3
-
, S4.Score As Score4
-
FROM ((((qryScores As MQ
-
LEFT JOIN (SELECT ID, Score FROM qryScores WHERE ScoreNum = 1) As S1 ON MQ.ID = S1.ID)
-
LEFT JOIN (SELECT ID, Score FROM qryScores WHERE ScoreNum = 2) As S2 ON MQ.ID = S2.ID)
-
LEFT JOIN (SELECT ID, Score FROM qryScores WHERE ScoreNum = 3) As S3 ON MQ.ID = S3.ID)
-
LEFT JOIN (SELECT ID, Score FROM qryScores WHERE ScoreNum = 4) As S4 ON MQ.ID = S4.ID)
Access sometimes doesn't like multiple joins without the parenthesis.
Thanks.
That eliminated that error, but now it's prompting for a Score parameter when I run the query.
Can you copy and paste into this thread what you have just in case there is an error somewhere?
- SELECT MQ.qID
-
, MQ.[sMonth]
-
, MQ.[rName]
-
, MQ.MgrName
-
, S1.Score AS [Score 1]
-
, S2.Score AS [Score 2]
-
, S3.Score AS [Score 3]
-
, S4.Score AS [Score 4]
-
FROM (((([ScoreCount] AS MQ
-
LEFT JOIN (SELECT qID, Score FROM [ScoreCount] WHERE ScoreNum = 1) As S1 ON MQ.qID = S1.qID)
-
LEFT JOIN (SELECT qID, Score FROM [ScoreCount] WHERE ScoreNum = 2) As S2 ON MQ.qID = S2.qID)
-
LEFT JOIN (SELECT qID, Score FROM [ScoreCount] WHERE ScoreNum = 3) As S3 ON MQ.qID = S3.qID)
-
LEFT JOIN (SELECT qID, Score FROM [ScoreCount] WHERE ScoreNum = 4) As S4 ON MQ.qID = S4.qID);
-
Well, nothing is obviously wrong. Try removing lines 6 through 8 and see if you get an error. Keep adding lines one at a time until you do receive the error and then let us know which one errors out.
I tried that and I still get the prompt to enter a Parameter Value for Score.
I also removed lines 10-12 but still get the prompt.
Any other ideas?
It sounds like the field name Score isn't accurate.
Okay, it was my fault. Had the Score field name wrong. Fixed that and I don't get the prompt, but it's not giving the expected results.
It's just listing the first score and showing a different row for each record still.
And the final query runs extremely slow.
Any ideas? I really appreciate your help on this.
Did you start back with the query from post #14 and fix the score field name? As NeoPa and JForbes said, a cross tab might be better since you have the ScoreNum field.
Yes fixed the Score field name.
Trying the crosstab again. I'll post results.
Do you know what NeoPa meant by "link in the data as a separate data source rather than use a Domain Aggregate function call" ?
Sounds like it might help the performance on the ScoreCount query that is getting the ScoreNum numbering.
You would create another subquery and use the Count() function. Try the following for your ScoreCount query: - SELECT T1.qID
-
, T1.sMonth
-
, T1.rName
-
, T1.MgrName
-
, T1.Score
-
, Count(T2.*) As ScoreNum
-
FROM tblScores As T1 LEFT JOIN
-
(SELECT * FROM tblScores) As T2
-
ON T1.rName = T2.rName AND T1.sMonth = T2.sMonth
I get this error when saving the query: "Syntax error in query expression 'Count(T2.*)'"
So I tried putting a field name: 'Count(T2.qID)' and that got past the error.
But when I ran the query, I got an error saying it did not include the specified expression 'qID' as part of an aggregate function--in reference to the qID in the SELECT statement at the beginning.
I really appreciate the help on this because I really want this to work. Using the other way with the DCount takes 45 seconds just to open that query, so I'm hoping the performance with this method can cut that down.
I added GROUP BY to the end and that solved the error. But it's just showing a total count for each person for each month on each row--not the incremental count.
Here's the query now: - SELECT T1.qID
-
, T1.sMonth
-
, T1.rName
-
, T1.MgrName
-
, T1.Score
-
, Count(T2.qID) As ScoreNum
-
FROM tblScores As T1 LEFT JOIN
-
(SELECT * FROM tblScores) As T2
-
ON T1.rName = T2.rName AND T1.sMonth = T2.sMonth
-
GROUP BY T1.qID, T1.sMonth, T1.rName, T1.MgrName, T1.qScore
Produces results like this: -
qID sMonth rName MgrName Score ScoreNum
-
1 Jan John George 92 3
-
2 Jan John George 94 3
-
3 Jan John George 98 3
-
4 Feb John George 97 2
-
5 Feb John George 91 2
Try removing the qID field from both the SELECT and GROUP BY clauses.
***Edit*** The above won't work. The Count function needs modified to only get records with lesser qID values that have matching sMonth and rName fields. I'm looking into this.
So ignore the fix from the previous post. Try adding the following to the end of line 9 of your last code:
That did it! And the performance is WAY better.
Thank you, Seth!
Here is the complete solution:
Step 1: Created a SourceCount query to provide numbered results for each person in each time period: - SELECT T1.qID
-
, T1.sMonth
-
, T1.rName
-
, T1.MgrName
-
, T1.Score
-
, Count(T2.qID) As ScoreNum
-
FROM tblScores As T1 LEFT JOIN
-
(SELECT * FROM tblScores) As T2
-
ON T1.rName = T2.rName AND T1.sMonth = T2.sMonth AND T1.qID <= T2.qID
-
GROUP BY T1.qID, T1.sMonth, T1.rName, T1.MgrName, T1.qScore
Which gives results like this: - qID sMonth rName MgrName Score ScoreNum
-
1 Jan John George 92 2
-
2 Jan John George 94 3
-
3 Jan John George 98 1
-
4 Feb John George 97 1
-
5 Feb John George 91 2
Step 2: Create a crosstab query: - TRANSFORM First([ScoreCount].qScore) AS Score
-
SELECT First([ScoreCount].[sMonth]), [ScoreCount].[rName], [ScoreCount].MgrName
-
FROM ScoreCount
-
GROUP BY [ScoreCount].[sMonth], [ScoreCount].[rName], [ScoreCount].MgrName
-
PIVOT [ScoreCount].[ScoreNum];
Which gives the desired final result: -
sMonth rName MgrName Score1 Score2 Score3
-
Jan John George 98 92 94
-
Feb John George 97 91
-
Thanks again for everyone's help!
Glad you got it to work. Good luck on your project.
NeoPa 32,462
Expert Mod 16PB
Congratulations Seth. Good work.
@Postman.
Please accept my apologies for leaving you without my response for so long. Work is keeping me very busy ATM and I don't get to visit as often as I'd like to. This is one I would have enjoyed too.
Luckily our Seth is getting more and more experienced and was able to resolve it for you.
Post your reply Sign in to post your reply or Sign up for a free account.
Similar topics
reply
views
Thread by glenn |
last post: by
|
2 posts
views
Thread by Omega |
last post: by
|
5 posts
views
Thread by jhutchings |
last post: by
|
4 posts
views
Thread by musicloverlch |
last post: by
| | | | | | | | | | | | | | |