I am a high school math teacher and my school's "data specialist." I am self-taught in Microsft Exel and Access, and I have been recently learning some of the SQL query language behind my usual Access work. I am comfortable with using Access queries to tie together data from many sources, such as exam scores from one source, English proficiency from a second source, and home phone number from a third source.
Here is a situation that I do not know how to do in Microsoft Access.
My math students take the New York state examination up to 3 times a year. They need a score of 80 to be considered "college ready."
Here are 3 sample tables. Each table uses the unique primary key "StudentID." The Integrated Algebra exam has the code MXRE.
Table #1 name: JanuaryAlgebra
StudentID Course Mark
201 MXRE 90
202 MXRE 55
203 MXRE 67
204 MXRE 80
205 MXRE 78
Note: Student #201 and #204 have finished the exam and do not take it again.
Table #2 name: JuneAlgebra
StudentID Course Mark
202 MXRE 70
203 MXRE 76
205 MXRE 81
206 MXRE 86
207 MXRE 78
There are two new students to the school, #206 and #207. Students #205 and #206 have finished the exam with high scores, and the remaining three students try the exam a third time.
Table #3 name: AugustAlgebra
StudentID Course Mark
202 MXRE 72
203 MXRE 83
207 MXRE 93
How do I return a query with one line for each StudentID displaying their highest exam score after the end of the school year???
Thanks!
Jeff
I'm not as familiar with Access, but I think it supports T-SQL. If it does then you can select all the rows in one statement and get the max. Though I realized when writing this answer that it's probably easier with a sub-select
In SQL it would look something like:
SELECT StudentId, Course, Max(Mark)
FROM (
SELECT StudentId, Course, Mark FROM JanuaryAlgebra
UNION
SELECT StudentId, Course, Mark FROM JuneAlgebra
UNION
SELECT StudentId, Course, Mark FROM AugustAlgebra
) as NewTable
GROUP BY StudentId, Course
I would suggest altering the table structure:
YourTable (Student_ID,Course,Mark,Date)
Then you can simply query:
SELECT Student_ID,Course,MAX(Mark) AS Max_Mark
FROM YourTable
--WHERE Course = 'MXRE' --If you wanted only algebra results.
GROUP BY Student_ID,Course
Multiple tables of identical structure almost never makes sense.
You can however use your current format to do this by unioning together all your tables in a subquery.
Related
I have trouble exactly explaining what my problem is. Let me start with what I am NOT asking: I am NOT asking for the minimal value of a column.
Assume the following table, which in one column lists names and in the other column lists guesses estimating the age of the person on the left. Multiple people are guessing so there are different guesses:
Name
AgeGuess
Max
34
Jennifer
21
Jordan
88
Max
29
Jennifer
22
Jordan
22
Jordan
36
...
...
and so on and so on. My question is: What is an SQL command that could give me a table filled by all names who were guessed the LEAST to be for example 36 (must be a specific value !). Additionally I'd like also like to know how often they were guessed 36. If nobody guessed them 36 I'd like to know that too.
In this example only Jordan was guessed to be 36. All the others were never guessed to be 36. I would expect an output like this:
Name
GuessedToBe36Count
Max
0
Jennifer
0
The table above is the result of me asking which people were guessed to be 36 the least amount of times.
My attempt was to group them by how often they were guessed 36. However if they were never rated 36, they also do not appear in the table at all, meaning I cannot just compute the minimum of the column.
If you want to get count of guessed ages by each user, group by user
SELECT name, COUNT(ageGuess) AS total, ageGuess FROM user_guess GROUP BY name, ageGuess ORDER BY name, total ASC
You will get then something similar to this:
name
total
ageGuess
Jordan
1
33
Jordan
3
65
Max
1
34
Please note that it will not return not guessed values. You can fill-in it when processing in back-end.
To have your wanted output, do it with sub-query:
SELECT name, (SELECT COUNT(ageGuess) FROM guesses g2 WHERE g2.name = g1.name AND ageGuess = 36) FROM guesses g1 GROUP BY name
Example
I'm trying to find the match no in which Germany played against Poland. This is from https://www.w3resource.com/sql-exercises/soccer-database-exercise/sql-subqueries-exercise-soccer-database-4.php. There are two tables : match_details and soccer_country. I don't understand how the count(distinct) works in this case. Can someone please clarify? Thanks!
SELECT match_no
FROM match_details
WHERE team_id = (
SELECT country_id
FROM soccer_country
WHERE country_name = 'Germany')
OR team_id = (
SELECT country_id
FROM soccer_country
WHERE country_name = 'Poland')
GROUP BY match_no
HAVING COUNT(DISTINCT team_id) = 2;
As Lamak mentioned, what an ugly consideration for a query, but many ways to approach a query.
As mentioned, counting for (Distinct team_id) makes sure that there are only 2 unique teams. If there is ever a Cartesian result, you could get repetition of multiple rows showing more than one instance of both teams. So the count of distinct on the TEAM_ID eliminates that.
Now, that said, Other "team" query data structures I have seen have a single record for the match and a column for EACH TEAM playing the match. That is easier by a long-shot, but still a relatively easy query.
Break the query down a little, and consider a large scale set of data (not that this, or any sort of even professional league would have such large record counts to give delay with a sql engine).
Your first criteria is games with Germany. So lets start with that.
SELECT
md1.match_no
FROM
match_details md1
JOIN soccer_country sc1
on md1.team_id = sc1.country_id
AND sc1.country_name = 'Germany'
So, why even look at any other record/match if Germany is not even part of the match on either side. Of which this in itself would return 6 matches from the sample data of 51 matches. So now, all you need to do is join AGAIN to the match details table a second time for only those matches, but ALSO the second team is Poland
SELECT
md1.match_no
FROM
match_details md1
JOIN soccer_country sc1
on md1.team_id = sc1.country_id
AND sc1.country_name = 'Germany'
-- joining again for the same match Germany was already qualified
JOIN match_details md2
on md1.match_no = md2.match_no
-- but we want the OTHER team record since Germany was first team
and md1.team_id != md2.team_id
-- and on to the second country table based on the SECOND team ID
JOIN soccer_country sc2
on md2.team_id = sc2.country_id
-- and the second team was Poland
AND sc2.country_name = 'Poland'
Yes, may be a longer query, but by eliminating 45 other matches (again, thinking a LARGE database), you have already saved blowing through tons of data to a very finite set. And now finishing only those Germany / Poland. No aggregates, counts, distincts, just direct joins.
FEEDBACK
Lets take a look at some BAD sample data... which as all programmers know, there is no such thing (NOT). Anyhow, lets take a look at these few matches.
Match Team ID blah
52 Poland Just put the names here for simplistic purposes
52 Poland
53 Germany
53 Germany
If you were to run the query without DISTINCT Teams, both match 52 and 53 would show up... As Poland is one team and appears 2 times for match 52, and similarly Germany 2 times for match 53. By doing DISTINCT Team, you can see that for each match, there is only 1 team being returned and thus excluded. Does that help? Again, no such thing as bad data :)
And yet another sample match where more than 2 teams created
Match Team ID
54 France
54 Poland
54 England
55 Hungary
56 Austria
In each of these matches, NONE would be returned. Match 54 has 3 distinct teams, and Match 55 and 56 only have single entry, thus no opponent to compete against.
2nd FEEDBACK
To clarify the query. If you look at the short query for just Germany, that aliased instance of "md1" is already sitting on any given record for a Germany match. So the second join to the "md2", I only care about the same match, so I can join on the same match_no. However, in the "md2" alias, the "!=" means NOT EQUAL. ! = logical NOT. So the join is saying from the MD1, join to the MD2 alias on the same match id. However, only give me where the teams are NOT the same. So the first instance holds Germany's team ID (already qualified) and thus give me the secondary team id. So now I can use the secondary (md2) instance team ID to join to the country to confirm only for Poland.
Does this now clarify things for you?
I have seen a similar question asked How to get second highest value among multiple columns in SQL ... however the solution won't work for Microsoft Access (Row_Number/Over Partition isn't valid in Access).
My Access query includes dozens of fields. I would like to create a new field/column that would return the second highest value of 10 specific columns that are included in the query, I will call this field "Cover". Something like this:
Product Bid1 Bid2 Bid3 Bid4 Cover
Watch 104 120 115 108 115
Shoe 65 78 79 76 18
Hat 20 22 19 20 20
I can do a really long SWITCH formula such as the following equivalent Excel formula:
IF( AND(Bid1> Bid2, Bid1 > Bid3, Bid1 > Bid4), Bid1,
AND(Bid2> Bid1, Bid2 > Bid3, Bid2 > Bid4), Bid2,
.....
But there must be a more efficient solution. A MAXIF equivalent would work perfectly if MS-Access Query had such a function.
Any ideas? Thank you in advance.
This would be easier if the data were laid out in a more normalized way. The clue is the numbered field names.
Your data is currently organized as a Pivot (known in Access as crosstab), but can easily be Unpivoted.
This data is much easier to work with if laid in a more normalized fashion which is this case would be:
Product Bid Amount
--------- ----- --------
Watch 1 104
Watch 2 120
Watch 3 115
Watch 4 108
Shoe 1 65
Shoe 2 78
Shoe 3 79
Shoe 4 76
Hat 1 20
Hat 2 22
Hat 3 19
Hat 4 20
This way querying becomes simpler.
It looks like you want the maximum of the bids, grouped by Product, so:
select Product, max(amount) as maxAmount
from myTable
group by product
Really, we shouldn't be storing text fields at all, so Product should be an ID number, with associated Product Names stored once in a separate table, instead of several times in the this one, like:
ProdID ProdName
-------- ----------
1 Watch
2 Shoe
3 Hat
... but that's another lesson.
Generally speaking repeating of anything should be avoided... that's pretty much the purpose of a database... but the links below will explain than I. :)
Quackit : Microsoft Access Tutorial
YouTube : DB Planning
Microsoft : Database Design Basics
Microsoft : Database Normalization Basics
Wikipedia : Database Normalization
Good day.
In my work I found a little problem. I think that I'm worse SQL-man. I can't solve two days.
I have a little sql table consist of informathion of students, classes and schools like
I need the serial number for each new (class and school) for each student in each class. Without PL/SQL
School Class Name
first 1b Smith
first 1b Jones
first 1b Willams
second 1a Taylor
second 1b Brown
second 1b Davies
And Table I need
Number School Class Name
1 first 1b Smith
2 first 1b Jones
3 first 1b Willams
1 second 1a Taylor
1 second 1b Brown
2 second 1b Davies
I know you solved it but I think anybody looking this up wants to see the full solution
SQL Fiddle Demo: http://sqlfiddle.com/#!4/a6756/8
SELECT
row_number() over (partition BY school, class ORDER BY school, class) as nr
, s.*
from students s
Now the counting of rows only is by school and class.
Whenever I deal with analytical functions I have to scratch my head a bit and usually refer always to this page which I find an excellent tutorial and memory refresher: http://www.orafaq.com/node/55
Edit:
Following the remark from Clockwork-Muse I have removed the remark about what the order bywithin the analytical function does and quote the Oracle documentation:
http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions004.htm#i81407
order_by_clause
Use the order_by_clause to specify how data is ordered within a
partition. For all analytic functions you can order the values in a
partition on multiple keys, each defined by a value_expr and each
qualified by an ordering sequence.
I've never posted here, so hoping this goes well :). I am using SQL Server 2008 R2 and I am trying to extract Student/Course information from a database. Here is what I am dealing with:
Table dbo.StudentsSchedule
StudentsSchedule table contains the following fields:
CRS_CODE
CRS_SECT
ID_NUMBER
Table dbo.StaffSchedule:
COURSE
SECTION
Teacher_ID
Here is what I am trying to accomplish:
I would like to combine the COURSE+SECTION CODE+Teacher_ID to use that as a Unique "New Course ID" and then attach a Student to it.
I've attempted this but I am getting way too many results. I am expecting around 300 but receiving over 10K+
SELECT dbo.StaffSchedule.COURSE+'-'+ dbo.StaffSchedule.SECTION+'-'+dbo.StaffSchedule.Teacher_ID) as [NewCourseID],
dbo.StudentSchedule.ID_NUMBER AS [StudentID],
from dbo.StaffSchedule INNER JOIN dbo.StudentSchedule ON
dbo.StaffSchedule.COURSE=dbo.StudentSchedule.CRS_CODE and
dbo.StaffSchedule.SECTION=dbo.StudentSchedule.CRS_SECT
Note that Teacher_ID can only exist once per COURSE+SECTION.
Any ideas? Am I doing this wrong?
Lets try to see it
Table dbo.StaffSchedule:
COURSE SECTION Teacher_ID
1 1 23
1 1 24
1 3 55
1 3 24
Table dbo.StudentsSchedule:
CRS_CODE CRS_SECT ID_NUMBER
1 1 44
1 1 45
1 3 89
1 3 44
This code:
SELECT dbo.StaffSchedule.COURSE+'-'+ dbo.StaffSchedule.SECTION+'-'+dbo.StaffSchedule.Teacher_ID) as [NewCourseID], dbo.StudentSchedule.ID_NUMBER AS [StudentID]
from dbo.StaffSchedule INNER JOIN dbo.StudentSchedule ON
dbo.StaffSchedule.COURSE=dbo.StudentSchedule.CRS_CODE and
dbo.StaffSchedule.SECTION=dbo.StudentSchedule.CRS_SECT
will return:
NewCourseID StudentID
1-1-23 44
1-1-23 45
1-1-24 44
1-1-24 45
1-3-55 89
1-3-24 89
1-3-55 44
1-3-24 44
May be the only problem I see is that for the same StudentID you have more than one value. I don't know what are you specting, so this is hoy much I can help you.
Sorry for my bad english! I hope this can help!
EDITE FOR NEW COMMENT
Is really simple to not use de Section in the NewCourseId
SELECT dbo.StaffSchedule.COURSE+'-'+dbo.StaffSchedule.Teacher_ID) as [NewCourseID], dbo.StudentSchedule.ID_NUMBER AS [StudentID]
from dbo.StaffSchedule INNER JOIN dbo.StudentSchedule ON
dbo.StaffSchedule.COURSE=dbo.StudentSchedule.CRS_CODE and
dbo.StaffSchedule.SECTION=dbo.StudentSchedule.CRS_SECT
But... what will happen?
The result will be:
NewCourseID StudentID
1-23 44
1-23 45
1-24 44
1-24 45
1-55 89
1-24 89
1-55 44
1-24 44
Look what happened whit the ID 1-24, it's look to has duplicated values, do you understand why? Look at the original tables again.
Sorry for my bad english!