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
Related
I need your help with an SQL query, that I am trying to build in C# Dataset Query Builder...
SELECT HouseHold.HHID, Client.FIRST_NAME, Client.LAST_NAME
FROM ((Client
INNER JOIN HouseHold_Client ON Client.CID = HouseHold_Client.CID)
INNER JOIN HouseHold ON HouseHold_Client.HHID = HouseHold.HHID)
Above code gives me the list of all HouseHolds (their ID) with Clients belonging to them:
HHID | FIRST_NAME | LAST_NAME
------------------------------
1 | Penelope | Grant
1 | Brian | Dyer
2 | James | Newman
2 | Richard | Parsons
.. but I can't figure out how to get people belonging to same HouseHold to show up on the same line, like this for a Data Grid View later on:
HHID | I_FIRST_NAME | I_LAST_NAME | II_FIRST_NAME | II_LAST_NAME
-----------------------------------------------------------------
1 | Penelope | Grant | Brian | Dyer
2 | James | Newman | Richard | Parsons
I have found loads of very similar questions, but very few had the same exact problem to solve. The ones (one or two) that really had the same problem and it had a solution, I just couldn't twist around my problem.
Any help is very much appreciated...
Thank you very much,
AD
Since you have only 2 persons per household, you can use the trick to get the minimum and maximum client Id per household. This is done in a subquery.
SELECT
X.HHID,
C1.FIRST_NAME AS I_FIRST_NAME, C1.LAST_NAME AS I_LAST_NAME,
C2.FIRST_NAME AS II_FIRST_NAME, C2.LAST_NAME AS II_LAST_NAME
FROM
(( SELECT
HHID, Min(CID) AS MinCId, IIf(Max(CID)=Min(CID), Null, Max(CID)) AS MaxCId
FROM HouseHold_Client
GROUP BY HHID
) X
INNER JOIN Client AS C1
ON X.MinCId = C1.CID)
LEFT JOIN Client AS C2
ON X.MaxCId = C2.CID;
The purpose of the IIf() expression is to output the maximum client Id only if it is different from the minimum client Id. To also return a record when MaxCId is Null, a LEFT JOIN is required on C2.
I did not join the HouseHold table here, since we only need the HHID from it, which is also available in HouseHold_Client. You can of course join it as well, if you need other columns from it.
Subquery:
( SELECT
HHID, Min(CID) AS MinCId, IIf(Max(CID)=Min(CID), Null, Max(CID)) AS MaxCId
FROM HouseHold_Client
GROUP BY HHID
) X
Subqueries must be enclosed in parentheses and be given a name (here X). X acts as a normal table having the columns HHID, MinCId and MaxCId in the main query. It is grouped by HHID. I.e., it returns one row per HHID. Min(CID) returns the smallest CID and Max(CID) largest CID per HHID.
In the case where you have 2 clients per HHID, this means that Min and Max will yield these 2 clients. If you have only 1 client, then both Min and Max will return the same client. If this is the case, then the IIf will return Null instead of Max(CID) to avoid returning twice the same client.
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 two models, Plans and Bookmarks, which are associated in a many-to-many relationship with an association table in the database. Specifically I'm looking at the situation where a Bookmark is associated with multiple Plans, like below...
BookmarkID | PlanID
A | 1
A | 2
B | 2
I'd want to select all BookmarkIDs where there is no association with a particular PlanID. So if PlanID = 1, I'd want to select B but not A.
For bonus points, I can easily take the BookmarkID result and get all the Bookmarks with a second linq query, but it would be cool to do this inline with a select function or soemthing.
I believe you want to use All like this:
int planId = 1;
var query = from b in context.Bookmarks
where b.Plans.All(p => p.PlanID != planId)
select b.BookmarkID;
i have a trouble to write a query with Linq i explain better my case, i have a database with 2 tables as follow :
it is the first table ;
Hotel
HotelID (Nvarchar(10) - PK)
HotelName (Nvarchar (200))
and this one is the second table ;
Period
PeriodID (Int (inc) - PK)
_From (Datetime )
_To (Datetime)
HotelID(Nvarchar(10) - FK)
then in the second Table (Period) there is the FK (HotelID) to connect the 2 tables;
Happen sometime i have a HotelName that gets more periods(PeriodID) so my purpose is to show the data in an only one Row into a DataGrid, i show you an example as i want show the data in my DataGrid if there are more periods in the same HotelName:
| HotelName | From | To | From(2) | To(2) | From(3) | To(3) | From(4)| To(4) |
| Excelsior |12/5/10 |3/6/10 | 2/8/10 | 9/9/10 | 23/9/10 | 1/10/10| 2/11/11| 1/12/10|
so i ask do you have any idea/suggest about how to show the data in a DataGrid inside one Row using Linq To Sql ?
thanks so much for your attention .
Have a good time .
Cheers
This article explains working with hierarchical data binding: http://msdn.microsoft.com/en-us/library/aa478959.aspx
Then, create an object model which roughly maps to your database tables:
Hotel
- ID
- Name
- Bookings
- Booking 1 { From, To }
- Booking 2 { From, To }
- Booking n { From, To }
Your Linq should look something like this:
var hotels = _db.Hotel.Select();
foreach(var hotel in hotels)
hotel.Bookings = _db.Period.Where(x => x.HotelId == hotel.HotelId).Select();
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.