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!
Related
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
I update a View to get in two columns the same value, but it interchanges the two values instead of just setting it. My (reduced for so) view UpdateADAuftrag2 is this.
SELECT dbo.CSDokument.AD1, dbo.UpdateAS400zuSellingBenutzer2.BenutzerNr
FROM dbo.AS400Auftrag
INNER JOIN
dbo.CSDokument ON dbo.AS400Auftrag.Angebotsnummer = dbo.CSDokument.Angebotsnummer
INNER JOIN
dbo.UpdateAS400zuSellingBenutzer2 ON dbo.AS400Auftrag.AD = dbo.UpdateAS400zuSellingBenutzer2.SchluesselWert
AND
dbo.CSDokument.AD1 <> dbo.UpdateAS400zuSellingBenutzer2.BenutzerNr
WHERE (dbo.AS400Auftrag.AD IS NOT NULL)
The important part is dbo.CSDokument.AD1 <> dbo.UpdateAS400zuSellingBenutzer2.BenutzerNr
AD1 is user number for external workers and BenutzerNr means user number. So e.g. the person Charlie Brown is an external worker and has the user number 31. When in AD1 is 31 - Charlie Brown is the external worker for this document (order in this case).
The Update statement loos like this
UPDATE [dbo].[UpdateADAuftrag2]
SET [AD1] = [BenutzerNr]
I have for example these values
AD1 | BenutzerNr
31 | 54
99 | 384
112 | 93
after the update the result is this
AD1 | BenutzerNr
54 | 31
384 | 99
93 | 112
Why not this?
AD1 | BenutzerNr
54 | 54
384 | 384
93 | 93
edit: UpdateAS400zuSellingBenutzer is also a View, but as far as I can see it includes only BenutzerNr and not AD1.
Firstly, you're never going to see your expected results in the view. Your UPDATE statement is effectively a DELETE statement (as far as the view is concerned). Rows only appear in the view if AD1 <> BenutzerNr, but you're setting them to be equal.
However, the documentation for updatable views states "Any modifications, including UPDATE, INSERT, and DELETE statements, must reference columns from only one base table." Your update statement references columns from more than one table.
https://msdn.microsoft.com/en-us/library/ms187956.aspx#Updatable Views
I'm not sure what you're trying to achieve here, but in my experience it's usually easier to issue the UPDATE statement against the base tables directly.
There were 2 bugs - Bug 1 View UpdateAS400zuSellingBenutzer2 had 2 results sometimes for one entry in CSDokument and Bug 2 There were 2 entries in Table AS400Auftrag and then it switched between these two entries. So it just looked like the SET switched the two entries but it was just by chance. Thanks for reading.
My main table, from which I take all the data from is "RequestTable" (I reduced it down to make it easier) in which I have:
ID_student
ID_professor
Date (and the three altogether are primary keys)
changeprofessor-note - if student wants to change the professor
then he/she should write in that field a sentence
why he/she wants to do the change
professor-reject-note - if the professor is not happy about the work of
the student, then he can choose not to mentor that
student anymore, leaving him without a mentor and the
student should choose another mentor later.
ID-seminar- after choosing a mentor the students
can choose the seminar they want to work on
changeofSeminar-note - if the student wants to change the seminar
then they need to write the reason why in here
(then the ID of the new seminar should be written in
the ID seminar field also)
IDapprove-reject - all approving or rejecting is going through this field
My initial theory was that the students could choose the mentor and the seminar in one row, but it seems too complicated now because I have no idea how to make everything work after changing mentors, declined mentoring, changing seminars and so on.
I set a more comfortable theory that all the students need to choose the mentor first. So that I could get easier the data of mentoring when needed. And I set "is null" in the query under the "ID_seminar" and "changeofseminar-note" because any changes on just the seminar part can't affect the rows where the students chosen their mentors/professors and got approved.
I implemented your code and got this:
SELECT [requesttable].ID_Student, Max([requesttable].Datum) AS MaxOfDatum, First([requesttable].ID_Profesor) AS ID_Profesor, [requesttable].ID_status_odobrenja
FROM [requesttable]
WHERE ((([requesttable].ID_Student) Not In (SELECT [ID_Student]
FROM [requesttable]
WHERE [IDapprove-reject] IS NOT NULL )))
GROUP BY [requesttable].ID_Student, [requesttable].IDapprove-reject, [requesttable].changeseminar-note, [requesttable].ID_seminar
HAVING ((([requesttable].IDapprovereject)=1) AND (([requesttable].changeseminar-note) Is Null) AND (([requesttable].Id_seminar) Is Null))
ORDER BY [requesttable].ID_Student, Max([requesttable].Datum), First([requesttable].ID_Profesor), [requesttable].IDapproved-reject;
And i get:
3 12 1
15 11 1
55 5 1
And I need:
3 6 1
15 6 1
52 5 1 - after being rejected by mentor 10,
the student choose another mentor (id 5) and got approved.
55 5 1
Old info below:
I got my query to this point and two other data are set to show only rows with null values to get this:
ID student Id professor date professor-reject-note ID accept/reject
3 12 12.11.2012 null 1
3 6 13.11.2012 null 1
52 10 12.11.2012 null 1
52 10 15.11.2012 NOT null 1
55 5 12.11.2012 null 1
I want my results to be
3 6 12.10.2013 null 1
15 6 7.1.2013 null 1
55 5 12.11.2012 null 1
Totally exclude StudentID 52 because of the professor-reject-note meaning the professor doesn't want to mentor the student anymore. Also I have a doubt about the ID accept/reject number in that option , maybe I could set it to 2 instead of 1 to make it easier. 1 means accepted, 2 would mean rejected, but if I set it to 2 and exclude the entire row I still can't get rid of the other ID 52 row. I'm a bit confused about it and have no clue how make it work.
If I set date to maxdate and Id professor to group by FIRST I almost get what I want, all the data is right except the Student ID 52 is still there - both rows.
You could use:
SELECT t.[id student],
t.[id professor],
t.DATE,
t.[professor-reject-note],
t.[id accept/reject]
FROM atable t
WHERE t.[id student] NOT IN
(SELECT [id student]
FROM atable
WHERE [professor-reject-note] IS NOT NULL)
Your field / column names could do with some work.
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.
I am using a MS SQL db and I have 3 tables: 'base_info', 'messages', 'config'
bases:
ID Name NameNum
====================================
1 Home 101
2 Castle 102
3 Car 103
messages:
ID Signal RecBy HQ
============================
111 120 Home 1
111 110 Castle 1
111 125 Car 1
222 120 Home 2
222 125 Castle 2
222 130 Car 2
333 100 Home 1
333 110 Car 2
config:
ID SignalRec SignalOut RecBy HQ
====================================
111 60 45 101 1
111 40 60 102 1
222 50 60 102 2
222 30 90 101 2
333 80 10 103 1
Ok so now I have a subquery in which I select the 'SignalRec' and 'SignalOut' from the config table and match it on the messages table by ID and Date(not included above), the problem is that I need it to match where messages.RecBy = config.RecBy but config.RecBy is a string but it's equivalent Name is in the bases table. So I almost need to do a subquery inside a subquery or some type of join and compare the returned value.
Here is what I have so far:
(SELECT TOP 1 config.SignalRec from config WHERE config.ID = messages.ID AND ||I need th other comparison here||...Order By...) As cfgSignalRec,
(SELECT TOP 1 config.SignalOut from config WHERE config.ID = messages.ID AND ||I need th other comparison here||...Order By...) As cfgSignalOut
I tried to make this as clear as possible but if you need more info let me know.
I would normalize out RecBy in your messages table to reference the bases table. Why would you insert the string content there if it's also referenced in bases?
This is exactly why normalization exists: reduce redundancy, reduce ambiguity, and enforce referential integrity.
To make this more clear, RecBy in the messages table should be a foreign key to Bases.
I think this could do the trick (although I have not tried it...)
SELECT
c.SignalRec
FROM config c
INNER JOIN bases b
ON c.RecBy = b.NameNum
INNER JOIN messages m
ON b.Name = m.RecBy
WHERE c.ID = m.ID
However, as Anthony pointed out, you probably want to normalize out the strings in the RecBy column in the messages table, as you have the same data in the bases table.
From your description, it just sounds like you need two JOINS
SELECT TOP 1
c.SignalRec
FROM
config c
INNER JOIN
bases b
ON c.RecBy = b.NameNum
INNER JOIN
messages m
ON b.Name = m.RecBy
I think I might have not been clear enough what I wanted to do, sorry about that.
The data is actually different in the 2 tables, although the correlations are the same. It's kind of confusing to explain without going into detail about how the system works.
I actually found a very fast way of doing this.
Inside my sub-query I do this:
(SELECT TOP 1 config.Signal FROM config,bases
WHERE config.ID = messages.ID AND bases.Name = messages.RecBy AND bases.NameNum =
config.RecBy Order By...)
So this essentially compares the 2 RecBy's of different tables even though one is an integer and the other is a string. It reminds me of a match and look up in Excel.