I have these two tables in MSSQL database.
Student Preferences Tables
(This table has preferences columns numbered from 1-7 in database)
------------------------------------------------------------------------------
Student Name | Preference 1| Preference 2 | Preference 3 |Group ID
-----------------------------------------------------------------------
Student A | Student G | Student F | Student G |
Student B | Student H | Student K | Student L |
Student C | Student I | Student A
Student D | Student H | Student K
Student E
Student F
Student G
Student H
Student I
Student J
Student K
Student L
-----------------------------------------------------------------------------
Groups Table
|Group ID |
---------
1
2
3
----------
I am creating groups of student based on preferences(preferred partners/team mates) entered by student.
Each group can have 5-8 students.Not all students will enter preferences.
To create a group i will check for the students who have entered 4-7 preferences and add them to a group.
For example, Student A has entered 4 preferences. Including student A now i have 5 students minimum number required for group. So, i would like to insert in "Groups table" and retrieve that number and insert in "Group ID" column for each student.
In cases if student has entered less than 4 preferences, i will have to create a new "group id" and assign to students but i also have to check that 5-8 students per group condition is not breached.
Can someone please guide me on this.
How to check for rows where more than 4 preference columns contain data(names)?
If students with more than 4 preferences exist, than how can i insert new record in Groups table(Group ID (auto-inc)) and retrieve it back to insert in Student Preference table.
How can i check 5-8 students condition is not breaching before inserting group id?
I am trying to find out how can these problems be solved (using c# or SQL) in easiest way?
I am writing application in C#.
That's a pretty horrible table design. You'd probably be a lot better off with multiple tables. One for student/group, and one for student/preference. So:
T_STUDENTS
StudentID
GroupID
T_STUDENT_PREFERENCES
StudentID
Preference
Then you could simply query your preferences table:
select
studentid,
count(preference)
from
pref_table
group by
studentid
having count(preference) >4
Since you can't do that, you'll have to do something gnarly with case statements.
Something like
select
student,
case when preference1 <>'' then 1 else 0 end as pref1 //or something to check for empty/null,
case when preference2 <>'' then 1 else 0 end as pref2
....
then add up the 7 columns and filter for your desired number of preferences.
Related
I have two tables, for example, Student and Grade.
Those two tables have a relationship with many-to-many, so the table is StudentGrade.
By using the .SelectMany query, I can retrieve all records which have a relation.
For example,
var myResult = myDb.Student.SelectMany(x => x.Grade).ToList();
But let say I add a new record just to the Student table, which has no relation with Grade, this new record cannot be retrieved by using the query above.
How can I retrieve all data including this new one?
Student
Id Name Age
1 AAA 4
2 BBB 5
3 CCC 6
4 DDD 7
Grade
Id Name
1 G1
2 G2
3 G3
4 G4
StudentGrade
Student Grade
2 1
2 2
2 3
3 3
Require result:
Id Name Age Grade
1 AAA 4
2 BBB 5 G1
2 BBB 5 G2
2 BBB 5 G3
3 CCC 6 G3
4 DDD 7
I found full outer join would help but will it work in a many-to-many relationship?
How can I overcome this issue ?
var result = (from s in myDb.Student
from g in myDb.Grades
where !g.Select(x => x.Student).Contains(s) || g.Student == null || g.Student == s).ToList();
As long as I understand your question this should give you
all Students that have grades,
all Grades with no students,
and all Students with no grades.
I have not seen your models but this should help
var myResult = myDb.Student.SelectMany(x => x.Grade).ToList();
This query "means" retrieve all the Grades that have a Student. If you want the Students, select Student and Include the Grades if you want.
var myResult = myDb.Students.Include(x => x.Grades).ToList();
I'm writing a zoo administration application, but i'm having trouble with making my database relations etc. I have 3 tables, Animals, Zones (Like artic or desert) and zoo's.
In the zoo's table there are all the zoo's somone owns.
In the animals table are all the animals and their details (Name gender etc.).
In the zones table there are all the zones.
What I want is that there is a zoo, that has a number of zones, for instance 4, and in all those zones there are animals.
Its easy to lay a relation between animals and zones, but how do i get it so that there can be multiple zones in a zoo.
Thanks in advance.
You can use intersection tables:
tbl_zoo (zoo_id, zoo_name)
itbl_zoo_zone (tbl_zoo.zoo_id, tbl_zones.zone_id)
tbl_zones (zone_id, zone_name)
itbl_animal_zones (tbl_zones.zone_id, tbl_animals.animal_id)
tbl_animals (animal_id, animal_name)
Here is a sample query:
SELECT zoos.Zoo_Name, anim.Animal_Name, zone.Zone_Name
FROM tbl_Zoo zoos
INNER JOIN itbl_Zoo_Zones zzoo ON zoos.zoo_id = zzoo.zoo_id
INNER JOIN tbl_zones zone ON zzoo.zone_id = zone.zone_id
INNER JOIN itbl_animal_zones azoo ON zone.zone_id = azoo.zone_id
INNER JOIN tbl_animals anim ON azoo.animal_id = anim.animal_id
Something like this would be a basic relationship. You have access to the Zoo an animal belongs to by joining through Zone.
table Zoo: ZooID (unique), ZooName, ...
table Zone: ZoneID (unique), ZooID (non-unique, FK), ZoneTypeID, ...
table Animal: AnimalID (unique), ZoneID (non-unique, FK), AnimalTypeID, ...
I would recommend adding a ZoneType and AnimalType table as well
table ZoneType: ZoneTypeID, ZoneName, ....
table AnimalType: AnimalTypeID, AnimalName, ....
Let's say 2 zoos had the same type of zones - arctic and desert. Without the ZoneType table your Zone table would look something like this:
ZoneID | ZooID | ZoneName
0 | 0 | Arctic
1 | 0 | Desert
2 | 1 | Arctic
3 | 1 | Desert
Now this is fine if the only data associated with a zone is its name, but imagine if there's more information on a zone - now all that data is duplicated for every row. With the ZoneType table you can store a single ZoneTypeID on the Zone table without duplcation any data
I'll create an Issue table in an MVC5 application and I want to use special code for each type of the issues as below:
For IT related questions INF-0001, INF-0002, ...
For General type of questions GEN-0001, GEN-0002, ...
As I use all the issues on the same table, I think it is better to store the ID numbers as INF-0001, GEN-0001, ... etc. In that case should I use string as the data type of ID column in MSSQL? Or what is the best approach in order to store Id's with their related codes? I also think of using GUID, but I am not sure if it is possible. Thanks in advance.
I suppose it's better create separate field for your custom names. So your table will have int Id (Primary Key) field and CustomName varchar(100) or nvarchar(100) type (If you use unicode characters) field with your custom names.
It will be better for perfomance to use int as Id if you will JOIN your file table with others. If you want to search values in this field and it is slow just create INDEX.
You could have a general issue id and a category, for example:
Table: Issue
------------------------------------
IssueID | CategoryID | CategoryIndex
------------------------------------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 1 | 3
Table: Category
-----------------------------
CategoryID | Prefix | Name
-----------------------------
1 | INF | IT
2 | GEN | General
Then you calculate the issue number when querying these tables.
You can store the calculated number in a table if you want to keep track of the issue number in case of a change in the database (ex: the prefix for IT related questions changes from INF to IT)
Now that you have a good schema, how do you keep control of the category sequence on the issues table? Check this out:
DECLARE #categoryID INT
DECLARE #nextSequence INT
SET #categoryID = 1 --You'll have to change this!
SELECT #nextSequence = i.CategoryIndex
FROM Issue i
WHERE i.CategoryID = #categoryID
SELECT COALESCE(#nextSequence, 0) + 1 as 'NextSequence'
You can turn that into a stored procedure (NextSequence, maybe?) that receives an INT as parameter (the category ID) and returns another INT as result (the CategoryIndex for the new issue).
Finally, to create your full code:
SELECT
i.IssueID
, c.Prefix + '-' + RIGHT('0000' + CONVERT(VARCHAR(4), i.CategoryIndex), 4) as 'IssueCode'
FROM Issue i
INNER JOIN Category c ON i.CategoryID = c.CategoryID
I have a table that I'm trying to query using Linq to SQL
The table is very simple it has 5 columns:
- PersonID
- ADID
- Name
- PlaceID
- PlaceName
I have 2 records in my table and they have the same PersonID in both records but different PlaceID and PlaceName values:
001 | 001 | Person X | P01 | Place 1
001 | 001 | Person X | P02 | Place 2
When I query this in SQL I get exactly the 2 rows:
select * from myTable where PersonID = '001'
However, when I try to do it in LINQ:
List<myTable> PersonInfo = (from myInfo in db.myTable
where myInfo.PersonID == "001"
select myInfo).ToList();
I get a count of 2 in PersonInfo but they are the same record. What am I doing incorrectly?
What I found out was that 1st Entity Framework needs a primary key to operate correctly. After researching the table I was using I found out that there was a primary key but it was a combo key So once I put "Entity Keys" on both columns my select statement returned the correct data.
Thanks to #GertArnold and everyone else that helped me on this problem!
I'm creating an Access DB for use in an C# application at school. I've not had much experience working with DB's so if this sounds stupid just ignore it. I want the user to be able to select all the classes that a certain student has had in our IT department. We have about 30 in all and the maximum that a person can take in 4 years of high school is 15. Right now my DB has 15 different columns for each class that a user could have. How can I compress this down to one column (if there is a way)?
Excellent question Lucas, and this delves into the act of database normalization.
The fact that you recognized why having multiple columns to represent classes is bad already shows that you have great potential.
What if we wanted to add a new class? Now we have to add a whole new column. There is little flexibility for this.
So what can be done?
We create THREE tables.
One table is for students:
Student
|-------------------------|
| StudentID | Student_Name|
|-------------------------|
| 1 | John |
| 2 | Sally |
| 3 | Stan |
---------------------------
One table is for Classes:
Class
------------------------
| ClassID | Class_Name|
------------------------
| 1 | Math |
| 2 | Physics |
------------------------
And finally, one table holds the relationship between Students and Classes:
Student_Class
-----------------------
| StudentID | ClassID |
-----------------------
If we wanted to enroll John into Physics, we would insert a row into the Student_Class table.
INSERT INTO Student_Class (StudentID, ClassID) VALUES (1, 2);
Now, we have a record saying that Student #1 (John) is attending Class #2 (Physics). Lets make Sally attend Math, and Stan attend Physics and Math.
INSERT INTO Student_Class (StudentID, ClassID) VALUES (2, 1);
INSERT INTO Student_Class (StudentID, ClassID) VALUES (3, 1);
INSERT INTO Student_Class (StudentID, ClassID) VALUES (3, 2);
To pull that data back in a readable fashion, we join the three tables together:
SELECT Student.Student_Name,
Class.Class_Name
FROM Student,
Class,
Student_Class
WHERE Student.StudentID = Student_Class.StudentID
AND Class.ClassID = Student_Class.ClassID;
This would give us a result set like this:
------------------------------
| Student_Name | Class_Name |
------------------------------
| John | Physics |
| Sally | Math |
| Stan | Physics |
| Stan | Math |
------------------------------
And that is how database normalization works in a nutshell.
So you have 15 columns (e.g. class1, class2, class3 ... class15)?
Looks like you have a classic many-to-many relationship. You should create a new table to relate students and classes.
student { StudentID, StudentName ... }
classes { ClassID, ClassName ... }
student_classes { StudentID, ClassID }
If you are tracking classes on a year-by-year basis, you could add a year column to the relationship as well:
student_classes { StudentID, Year, ClassID }
It sounds like you need to think about normalizing your database schema.
There is a many-to-many relationship between students and classes such that many students can take many classes and many classes can be taken by many students. The most common approach to handling this scenario is to use a junction table.
Something like this
Student Table
-------------
id
first_name
last_name
dob
Class Table
-----------
id
class_name
academic_year
Student_Class Table
-------------------
student_id
class_id
year_taken
Then your queries would join on the tables, for example,
SELECT
s.last_name + ', ' + s.first_name AS student_name,
c.class_name,
sc.year_taken
FROM
student s
INNER JOIN
student_class sc
ON
s.id = sc.student_id
INNER JOIN
class c
ON
sc.class_id = class.id
ORDER BY
s.last_name, sc.year_taken
One word of advice that I would mention is that Access requires you to use parentheses when joining more than table in a query, I believe this is because it requires you to specify an order in which to join them. Personally, I find this awkward, particularly when I am used to writing a lot of SQL without designers. Within Access, I would recommend using the designer to join tables, then modify the generated SQL for your purposes.
This is a normalisiation issue. In effect you are asking the wrong question. In stead ask yourself the question how can you store 0 or more classes_taken? What other details do you need to store about each class taken? E.g. just the class taken, or data taken, result, etc?
For example consider somethin like the following
table Student
id int
name varchar(25)
...
table classes
id int
name varchar(25)
...
table clases_taken
student_id int (foreign key to student.id)
class_id int (foreign key to class.id)
data_started datatime
result varchar(5)
tutor_id int (foreign key to tutor.id)
...
You should never have columns like class1, class2, class3, class4 etc in a database table. What you should have is a related table. Your stucture would be something like:
Student Table with the following columns
StudentID
StudentLastName
StudentFirstName
(and so forth for all the data to describe a student)
Then
Course table with the following columns
CourseId
CourseName
Then
StudentCourse Table with the following columns
StudentId
CourseID
CourseDate
Now to find out what courses the person took you join these tables together.
Something like:
Select StudentID,StudentLastName,StudentFirstName, CourseName, CourseDate
from Student
join StudentCourse on student. studentid = StudentCourse.StudentID
join Course on Course.courseID = StudentCourse.CourseID
Please read this link to start learning database fundamentals:
http://www.deeptraining.com/litwin/dbdesign/FundamentalsOfRelationalDatabaseDesign.aspx
How about no class columns in the student table. Setup a new table with student id and class id columns. Each row represents a class the student took. Maybe add more columns such as: the year/semester, grade, etc.