Representing a timetable in a database - sql

I want to represent a timetable on a mysql database.
I had the idea that I should have three tables:
a classdetails table - containing class capacity, classroom name, etc.
a class_sessions table with: start_time and end_time of session,
a class_unit table with: the name of the course (MAT003. et.c)
there would also be appropriate foreign keys in the class_sessions table and class_unit table.
Eventually I want to be able to query for a 'free' class (one that does not have a class presently, at the time of running of the query) and return its name e.g (Room 5b)
Will the tables I have listed be sufficient for the query at hand?
Any ideas how to make this better will be appreciated.

This does what you said, but I'm still not 100% confident that what you said is what you want. :-)
CREATE TABLE rooms (
room_num VARCHAR(10) NOT NULL PRIMARY KEY
);
INSERT INTO rooms VALUES
('5B'),
('5C'),
('5D');
CREATE TABLE class_rooms (
class VARCHAR(15) NOT NULL,
room_num VARCHAR(10) NOT NULL,
CONSTRAINT room_nm_fm_rooms FOREIGN KEY (room_num) REFERENCES rooms(room_num),
PRIMARY KEY (class, room_num)
);
INSERT INTO class_rooms VALUES
('Algebra', '5B'),
('Calculus','5C'),
('Discrete Math', '5C');
Having done that, one way to get the room number that's not in use is with a query using SELECT...WHERE...NOT IN. This probably isn't the fastest, but in my experience it's the easiest syntax to understand.
SELECT room_num
FROM rooms
WHERE room_num NOT IN (SELECT room_num FROM class_rooms);

Related

Is a single field contain multiple foreign key relationship from different table [SQL]

I have 3 table Student,Teacher,User.
Student:
CREATE TABLE Student( id INT NOT NULL PRIMARY KEY,name VARCHAR(50) NOT NULL);
INSERT INTO [dbo].[Student]([id],[name]) VALUES(4,'Ram'),(5,'Raman');
Teacher:
CREATE TABLE Teacher( id INT NOT NULL PRIMARY KEY,name VARCHAR(50) NOT NULL);
INSERT INTO [dbo].[Student]([id],[name]) VALUES(1,'Raj'),(2,'Rahul');
User:
CREATE TABLE [dbo].[User](
id INT NOT NULL PRIMARY KEY,
user_id INT NOT NULL,
user_type CHAR(1) NOT NULL,
user_name VARCHAR(10) NOT NULL,
user_password VARCHAR(255) NOT NULL,
CONSTRAINT FOREIGN KEY (user_id) REFERENCES Student (id),
CONSTRAINT FOREIGN KEY (user_id) REFERENCES Teacher (id) );
Now I try to INSERT in User table with below query
INSERT INTO [dbo].[User] ([id] ,[user_id] ,[user_type],[user_name] ,[user_password]) VALUES (1 ,1,'S','Raj_001','********')
It gives me error for violation of foreign key due to
value of user_id is available in Teacher and not in Student
So my question is: How can I achieve that a value of user_id is present in one of those table and data should be inserted in User table.
Your table structure is flawed. A foreign key tells the database that there is definitely one and only one row on one side of the relationship. You can't have a partial match, it's all or nothing. This is before considering how you would ensure that you don't end up with the same id in both the teacher and student table.
It would be better to have two columns in your user table, one for teacher id and one for student id. In fact going further given the only extra data in both student and teacher tables is their name why not just eliminate both and store the name in the user table?
Another option to consider is that your foreign key is pointed in the wrong direction. Perhaps a better approach is reversing it to ensure each student and teacher is a user rather than that a user is either a student or a teacher.
First of all get rid of those key words from table name like [User],user_id etc.
It really is problematic and irritating.
Secondly why 2 key in [User] table,id, user_id ? It is not require.
I will keep only id or user_id.
Thirdly, knowing the real table structure or even purpose of each table help in better data modeling.
From [User] table what it appear is that id and user_type are composite primary key.
It should be. If this is true then you can't define FK constraint, as user_type is not available in either Teacher table and Student Table.
And what is appear that ,for example first data is inserted in Student or Teacher then data is inserted in User table in same Transaction.
So in all above scenario, Instead of Trigger is ideal scenario in this condition.
My script is just demo,
Create Proc spStudentInsert
as
set nocount on
set xact_abort on
begin try
begin tran
--bulk insert or single insert ,no problem
insert into Student
insert into [User]
if (##Trancount>0)
commit
end try
begin catch
if (##Trancount>0)
rollback
end catch
CREATE TRIGGER INSTEADOF_TR_I_User ON [user]
INSTEAD OF INSERT
AS
BEGIN
DECLARE #Flag BIT = 1
IF NOT EXISTS (
SELECT 1
FROM Student S
INNER JOIN inserted i ON i.id = S.id
)
SET #Flag = 0
ELSE IF NOT EXISTS (
SELECT 1
FROM Teacher T
INNER JOIN inserted i ON i.id = T.id
)
AND #Flag = 1
SET #Flag = 0
IF (#Flag = 0)
BEGIN
RAISERROR (
N'Invalid user'
,16
,1
)
RETURN
END
END
In case I am wrong about id, user_type composite PK then you can do other way,
PK of User id is FK in Student table as well as Teacher table.
Also , id are PK in their respective table.
So first you insert in User table then you insert in Student or Teacher table.
So design in this case will be,
CREATE TABLE [dbo].[User](
id INT NOT NULL ,
user_type CHAR(1) NOT NULL,
user_name VARCHAR(10) NOT NULL,
user_password VARCHAR(255) NOT NULL,
CONSTRAINT [PK_user] PRIMARY KEY (id)
)
INSERT INTO [dbo].[User] ([id] ,[user_type],[user_name] ,[user_password])
VALUES (1 ,1,'S','Ram_001','********')
--drop table [User]
--alter table [user]
-- drop constraint PK_user
CREATE TABLE Student( id INT NOT NULL PRIMARY KEY,name VARCHAR(50) NOT NULL);
ALTER TABLE Student
add CONSTRAINT FK_StudentUser FOREIGN KEY (id) REFERENCES [User] (id);
INSERT INTO [dbo].[Student]([id],[name]) VALUES(1,'Ram'),(5,'Raman');
--select * from [Student]
CREATE TABLE Teacher( id INT NOT NULL PRIMARY KEY,name VARCHAR(50) NOT NULL);
ALTER TABLE Teacher
add CONSTRAINT FK_TeacherUser FOREIGN KEY (id) REFERENCES [User] (id);
INSERT INTO [dbo].Teacher([id],[name]) VALUES(1,'Raj'),(2,'Rahul');
So what it appear from your question, I will create Instead of Trigger and go with that model.
There are two ways to do this without re-doing your table schema
Create a 4th table that contains the union of ID from Student and Teacher. Presumably, you would insert to that table whenever you insert into Student and Teacher, and then have the constraint act against that table.
Create a custom function based constraint rather than a foreign key which looks up against a union of both the student and teacher tables.
Neither of these are great/clean solutions, and as others have noted, you probably are dealing with the fact that the schema isn't ideal.
Still, if you're just modifying an existing system (and I assume this is a simplified version of what you're actually dealing with), then one of the two solutions I mentioned id easier than redoing the schema.
Your foreign key definition has some logical problems. It forces the user_id to exists in both tables. The solution here is depended on the business needs and real data.
You can create a Person table with 1-1 relation to the student and the Teacher tables and then use the Person.Id column in the foreign key definition. This solution assumes that the students' and teachers' data may change differently.
As another way (which is explained in other answers), If your student and teachers' data is similar, you can combine both tables, and difference data by one added "Type" column.
SO you want to tell the system that your User must be in one of your tables .
it's not possible in databases logic but you can write a script that have a condition (IF exist) then insert you user data
notice : you have to remove your foreign keys .
its a wrong logic !
you are telling your system that your user is a student and a teacher to !
that is absolutely wrong .
I feel like there were some excellent responses in this thread, but I'm going to take a stab at giving you a different direction. I'll try to be clear on why, and try to acknowledge your situation as I do so.
Student/Teacher Data is Often Messy
As someone with experience normalizing data sets in higher education, the issue you've run into resonated with me. Educational users could be in all three categories (Student, Teacher, and User) or just one of them, depending on the how and why the category was linked. Worse, they can enter from multiple directions and end up with multiple unlinked accounts. More mature institutions and tools have protections against this, but I still see user-created databases and ten year old 'it was temporary' solutions that cause me existential pain.
The Main Stumbling Block
Any database with tables that independently define who is a user based on different criteria have a potential point of failure.
Foreign keys was the right direction to be thinking in for this problem. You want these tables to connect and you want them to stay consistent with one another, regardless of which side of the data gets altered. We just need to add a little extra.
One Table To Rule Them All
Before I go further, I want to say that it is possible to get all of the fields you're tracking into a single table, but having multiple tables with distinct purposes is an easy way to protect against changes later.
The foreign key table must inherit the key from another table, but people often say foreign keys can't be primary keys as well. Why?
Foreign keys are not automatically unique keys in the tables they're in. If there can be multiple fields tied to that same key, the table ends up worthless.
We fix that with the Unique constraint. Applied to a foreign key field, Unique essentially makes it act as a primary key would.
Sample Method
Below is an alternative design for what you seemed to be after, creating a master list of IDs that can link across all tables. I tossed in a few minor tracking fields that can be useful for debugging.
/*Create Tables*/
CREATE TABLE ID(
USER_ID int NOT NULL PRIMARY KEY AUTO_INCREMENT,
USER_CREATED timestamp
);
CREATE TABLE USER(
USER_ID int NOT NULL UNIQUE FOREIGN KEY REFERENCES ID(USER_ID),
USER_LOGIN VARCHAR(10) NOT NULL UNIQUE,
USER_PASSWORD VARCHAR(255) NOT NULL,
USER_NAME VARCHAR(50) NOT NULL
);
CREATE TABLE PERMISSIONS(
USER_ID int NOT NULL UNIQUE FOREIGN KEY REFERENCES ID(USER_ID),
STUDENT CHAR(1),
TEACHER CHAR(1)
);
This creates a flag for student and teacher that could both be true or both be false. If you want the code to force them into only one or the other, you can still have the permissions table do a USER_TYPE field instead. I suggest a null or neither value being possible in either case if you plan to use this for any length of time. Best of luck.

SQL 'Average' dilemma

I'm fairly new to SQL; For my university project we're creating a database for games, and reviewing said games. My issue is that I have a Table titled "Games", where it includes multiple attributes including a derived attribute 'Rating'; another table exists which is Member_rates_games, which includes 4 values, Uniqueness, Graphics, Design, and Interactivity. Now the issue is I don't know how to compute the 'Rating' Attribute using these 4 values in the other table. I Tried rating AS AVG(Uniquness, Interactivity, Design, Graphics), but it didn't work, the error being that it needs an argument. So how do I solve this? Do I resort to Joins? or is there another work around?
Here's the Schema if it can help:
Games (game_ID, name, release_date, age_limit, rating, email*)
Games_Rates_Members (game_ID, email, design, interactivity, graphics, uniqueness)
Any help would be greatly appreciated. I'm using Visual Studio w/SQL Server, Not MYSQL. Thanks in advance.
EDIT: Looks like I worded the problem poorly, let my try again, So this is my current SQL Code:
CREATE TABLE Games(
game_id int IDENTITY,
name varchar (30) NOT NULL,
release_date date,
age_limit int NOT NULL,
rating int,
email varchar (50) NOT NULL,
CONSTRAINT PK_Games PRIMARY KEY (game_id),
CONSTRAINT FK_Games FOREIGN KEY (email) References Development_teams )
CREATE TABLE Games_Rates_Members(
game_id int NOT NULL,
email varchar (50) NOT NULL,
design int NOT NULL,
interactivity int NOT NULL,
graphics int NOT NULL,
uniqueness int NOT NULL,
CONSTRAINT PK_Games_Rates_Members PRIMARY KEY (game_id, email),
CONSTRAINT FK_Games_Rates_Members_1 FOREIGN KEY (game_id) References Games,
CONSTRAINT FK_Games_Rates_Members_2 FOREIGN KEY (email) References Members
)
Now, my issue is when I insert a value to the games table, in the rating attribute, what do I do in order for this rating attribute to be equivalent to the average of the 4 Values in the Games_Rates_Members Table. I hope this is more clear, excuse my English not being clear enough. Thanks again.
I think it is poor design to expect a value to populated automatically in the games table. This would mean every change to the ratings table would cascade a change to the games table.
This is not a leading or best practice with relational databases. In a relation database you define the relations of the data, not the data generation rules. Leave that to your select statements. You want to get an average for every game calculate it when you select the game. You could do that like this:
SELECT Games.game_id, AVG((GRM.design,GRM.interactivity,GRM.graphics,GRM.uniqueness)/4) as rating
FROM Games
JOIN Games_Rates_Members GRM ON Games.game_id = GRM.game_id
GROUP BY Games.game_id
Sidenote, I do not recommend using email as a user key. What happens if someone changes their email? Instead use an assigned unique integer key as the key.
Assuming those 4 values are numeric and you have many reviews for the same game from different users.
select game_ID, avg((design + interactivity + graphics + uniqueness)/4) as rating
from Games_Rates_Members
group by game_ID

Two Primary keys that are the same, but in two different tables

I just have a quick question for ya's about primary keys in SQL. I have a primary key in one table (Patient) and another table (Facility) with a different primary key. What I want to do is connect them so I have my primary key from Patient and have that exact primary key (with data) in my Facility table. How do I go about doing this? Thanks for any help in advance, it is greatly appreciated!
Add an other table ( eg hospitalization ) that contains both keys:
create table hospitalization (
patient_id int not null,
facility_id int not null,
date_start date not null,
date_end date
);
this is a standard many to many relation with properties and means that a patient could be hospitalized many times and each facility could have many patients.
This is an interesting kind of relation. But you can do it inserting the same id to both tables:
INSERT INTO Parient(ID, NAME) VALUES (5, 'Mike');
INSERT INTO Facility(ID, LOCATION) VALUES (5, 'San Francisco');
You can alos use a sequence for the first insert and then use generated new id for the second insert (current value).
Note: I do not recommend this practice of ID synchronization. The better way to go is to let your database assign unique IDs for us (using sequence of auto-increment) and then define foreign key constraint adding FACILITY_ID to the Patient table or PATIENT_ID to the Facility table implementing one-to-one relationship.

How do you store business activities in a SQL database?

The goal is to store activities such as inserting, updating, and deleting business records.
One solution I'm considering is to use one table per record to be tracked. Here is a simplified example:
CREATE TABLE ActivityTypes
(
TypeId int IDENTITY(1,1) NOT NULL,
TypeName nvarchar(50) NOT NULL,
CONSTRAINT PK_ActivityTypes PRIMARY KEY (TypeId),
CONSTRAINT UK_ActivityTypes UNIQUE (TypeName)
)
INSERT INTO ActivityTypes (TypeName) VALUES ('WidgetRotated');
INSERT INTO ActivityTypes (TypeName) VALUES ('WidgetFlipped');
INSERT INTO ActivityTypes (TypeName) VALUES ('DingBatPushed');
INSERT INTO ActivityTypes (TypeName) VALUES ('ButtonAddedToDingBat');
CREATE TABLE Activities
(
ActivityId int IDENTITY(1,1) NOT NULL,
TypeId int NOT NULL,
AccountId int NOT NULL,
TimeStamp datetime NOT NULL,
CONSTRAINT PK_Activities PRIMARY KEY (ActivityId),
CONSTRAINT FK_Activities_ActivityTypes FOREIGN KEY (TypeId)
REFERENCES ActivityTypes (TypeId),
CONSTRAINT FK_Activities_Accounts FOREIGN KEY (AccountId)
REFERENCES Accounts (AccountId)
)
CREATE TABLE WidgetActivities
(
ActivityId int NOT NULL,
WidgetId int NOT NULL,
CONSTRAINT PK_WidgetActivities PRIMARY KEY (ActivityId),
CONSTRAINT FK_WidgetActivities_Activities FOREIGN KEY (ActivityId)
REFERENCES Activities (ActivityId),
CONSTRAINT FK_WidgetActivities_Widgets FOREIGN KEY (WidgetId)
REFERENCES Widgets (WidgetId)
)
CREATE TABLE DingBatActivities
(
ActivityId int NOT NULL,
DingBatId int NOT NULL,
ButtonId int,
CONSTRAINT PK_DingBatActivities PRIMARY KEY (ActivityId),
CONSTRAINT FK_DingBatActivities_Activities FOREIGN KEY (ActivityId)
REFERENCES Activities (ActivityId),
CONSTRAINT FK_DingBatActivities_DingBats FOREIGN KEY (DingBatId)
REFERENCES DingBats (DingBatId)
CONSTRAINT FK_DingBatActivities_Buttons FOREIGN KEY (ButtonId)
REFERENCES Buttons (ButtonId)
)
This solution seems good for fetching all activities given a widget or dingbat record id, however it doesn't seem so good for fetching all activities and then trying to determine to which record they refer.
That is, in this example, all the account names and timestamps are stored in a separate table, so it's easy to create reports focused on users and focused on time intervals without the need to know what the activity is in particular.
However, if you did want to report on the activities by type in particular, this solution would require determining to which type of activity the general activity table refers.
I could put all my activity types in one table, however the ID's would not be able to be constrained by a foreign key, instead the table name might be used as an id, which would lead me to use dynamic queries.
Note in the example that a DingBatActivity has an optional button Id. If the button name were to have been edited after being added to the dingbat, the activity would be able to refer to the button and know its name, so if a report listed all activities by dingbat and by button by name, the button name change would automatically be reflected in the activity description.
Looking for some other ideas and how those ideas compromise between programming effort, data integrity, performance, and reporting flexibility.
The way that I usually architect a solution to this problem is similar to inheritance in objects. If you have "activities" that are taking place on certain entities and you want to track those activities then the entities involved almost certainly have something in common. There's your base table. From there you can create subtables off of the base table to track things specific to that subtype. For example, you might have:
CREATE TABLE Objects -- Bad table name, should be more specific
(
object_id INT NOT NULL,
name VARCHAR(20) NOT NULL,
CONSTRAINT PK_Application_Objects PRIMARY KEY CLUSTERED (application_id)
)
CREATE TABLE Widgets
(
object_id INT NOT NULL,
height DECIMAL(5, 2) NOT NULL,
width DECIMAL(5, 2) NOT NULL,
CONSTRAINT PK_Widgets PRIMARY KEY CLUSTERED (object_id),
CONSTRAINT FK_Widgets_Objects
FOREIGN KEY (object_id) REFERENCES Objects (object_id)
)
CREATE TABLE Dingbats
(
object_id INT NOT NULL,
label VARCHAR(50) NOT NULL,
CONSTRAINT PK_Dingbats PRIMARY KEY CLUSTERED (object_id),
CONSTRAINT FK_Dingbats_Objects
FOREIGN KEY (object_id) REFERENCES Objects (object_id)
)
Now for your activities:
CREATE TABLE Object_Activities
(
activity_id INT NOT NULL,
object_id INT NOT NULL,
activity_type INT NOT NULL,
activity_time DATETIME NOT NULL,
account_id INT NOT NULL,
CONSTRAINT PK_Object_Activities PRIMARY KEY CLUSTERED (activity_id),
CONSTRAINT FK_Object_Activities_Objects
FOREIGN KEY (object_id) REFERENCES Objects (object_id),
CONSTRAINT FK_Object_Activities_Activity_Types
FOREIGN KEY (activity_type) REFERENCES Activity_Types (activity_type),
)
CREATE TABLE Dingbat_Activities
(
activity_id INT NOT NULL,
button_id INT NOT NULL,
CONSTRAINT PK_Dingbat_Activities PRIMARY KEY CLUSTERED (activity_id),
CONSTRAINT FK_Dingbat_Activities_Object_Activities
FOREIGN KEY (activity_id) REFERENCES Object_Activities (activity_id),
CONSTRAINT FK_Dingbat_Activities_Buttons
FOREIGN KEY (button_id) REFERENCES Object_Activities (button_id),
)
You can add a type code to the base activity if you want to for the type of object which it is affecting or you can just determine that by looking for existence in a subtable.
Here's the big caveat though: Make sure that the objects/activities really do have something in common which relates them and requires you to go down this path. You don't want to store disjointed, unrelated data in the same table. For example, you could use this method to create a table that holds both bank account transactions and celestial events, but that wouldn't be a good idea. At the base level they need to have something in common.
Also, I assumed that all of your activities were related to an account, which is why it's in the base table. Anything in common to ALL activities goes in the base table. Things relevant to only a subtype go in those tables. You could even go multiple levels deep, but don't get carried away. The same goes for the objects (again, bad name here, but I'm not sure what you're actually dealing with). If all of your objects have a color then you can put it in the Objects table. If not, then it would go into sub tables.
I'm going to go out on a limb and take a few wild guesses about what you're really trying to accomplish.
You say you're trying to track 'store activities' I'm going to assume you have the following activities:
Purchase new item
Sell item
Write off item
Hire employee
Pay employee
Fire employee
Update employee record
Ok, for these activities, you need a few different tables: one for inventory, one for departments, and one for employees
The inventory table could have the following information:
inventory:
item_id (pk)
description (varchar)
number_in_stock (number)
cost_wholesale (number)
retail_price (number)
dept_id (fk)
department:
dept_id (pk)
description (varchar)
employee
emp_id (pk)
first_name (varchar)
last_name (varchar)
salary (number)
hire_date (date)
fire_date (date)
So, when you buy new items, you will either update the number_in_stock in inventory table, or create a new row if it is an item you've never had before. When you sell an item, you decriment the number_in_stock for that item (also for when you write off an item).
When you hire a new employee, you add a record from them to the employees table. When you pay them, you grab their salary from the salary column. When you fire them, you fill in that column for their record (and stop paying them).
In all of this, the doing is not done by the database. SQL should be used for keeping track of information. It's fine to write procedures for doing these updates (a new invoice procedure that updates all the items from an invoice record). But you don't need a table to do stuff. In fact, a table can't do anything.
When designing a database, the question you need to ask is not "what do I need to do?" it is "What information do I need to keep track of?"
New answer, based on an different interpretation of the question.
Are you just trying to keep a list of what has happened? If you just need a ordered list of past events, you just need 1 table for it:
action_list
action_list_id (pk)
action_desc (varchar)
event_log:
event_log_id (pk)
event_time (timestamp)
action_list_id (fk)
new_action_added (fk)
action_details_or_description (varchar)
In this, the action_list would be something like:
1 'WidgetRotated'
2 'WidgetFlipped'
3 'DingBatPushed'
4 'AddNewAction'
5 'DeleteExistingAction'
The event_log would be a list of what activities happened, and when. One of your actions would be "add new action" and would require the 'new_action_added' column to be filled in on the event table anytime the action taken is "add new action".
You can create actions for update, remove, add, etc.
EDIT:
I added the action_details_or_description column to event. In this way, you can give further information about an action. For example, if you have a "product changes color" action, the description could be "Red" for the new color.
More broadly, you'll want to think through and map out all the different types of actions you'll be taking ahead of time, so you can set up your table(s) in a way that can accurately contain the data you want to put into them.
How about the SQL logs?
The last time I needed a database transaction logger I used an Instead Of trigger in the database so that it would instead of just updating the record, the database would insert a new record into the log table. This technique meant that I needed an additional table to hold the log for each table in my database and the log table had an additional column with a time stamp. Using this technique you can even store the pre and post update state of the record if you want to.

Polymorphism in SQL database tables?

I currently have multiple tables in my database which consist of the same 'basic fields' like:
name character varying(100),
description text,
url character varying(255)
But I have multiple specializations of that basic table, which is for example that tv_series has the fields season, episode, airing, while the movies table has release_date, budget etc.
Now at first this is not a problem, but I want to create a second table, called linkgroups with a Foreign Key to these specialized tables. That means I would somehow have to normalize it within itself.
One way of solving this I have heard of is to normalize it with a key-value-pair-table, but I do not like that idea since it is kind of a 'database-within-a-database' scheme, I do not have a way to require certain keys/fields nor require a special type, and it would be a huge pain to fetch and order the data later.
So I am looking for a way now to 'share' a Primary Key between multiple tables or even better: a way to normalize it by having a general table and multiple specialized tables.
Right, the problem is you want only one object of one sub-type to reference any given row of the parent class. Starting from the example given by #Jay S, try this:
create table media_types (
media_type int primary key,
media_name varchar(20)
);
insert into media_types (media_type, media_name) values
(2, 'TV series'),
(3, 'movie');
create table media (
media_id int not null,
media_type not null,
name varchar(100),
description text,
url varchar(255),
primary key (media_id),
unique key (media_id, media_type),
foreign key (media_type)
references media_types (media_type)
);
create table tv_series (
media_id int primary key,
media_type int check (media_type = 2),
season int,
episode int,
airing date,
foreign key (media_id, media_type)
references media (media_id, media_type)
);
create table movies (
media_id int primary key,
media_type int check (media_type = 3),
release_date date,
budget numeric(9,2),
foreign key (media_id, media_type)
references media (media_id, media_type)
);
This is an example of the disjoint subtypes mentioned by #mike g.
Re comments by #Countably Infinite and #Peter:
INSERT to two tables would require two insert statements. But that's also true in SQL any time you have child tables. It's an ordinary thing to do.
UPDATE may require two statements, but some brands of RDBMS support multi-table UPDATE with JOIN syntax, so you can do it in one statement.
When querying data, you can do it simply by querying the media table if you only need information about the common columns:
SELECT name, url FROM media WHERE media_id = ?
If you know you are querying a movie, you can get movie-specific information with a single join:
SELECT m.name, v.release_date
FROM media AS m
INNER JOIN movies AS v USING (media_id)
WHERE m.media_id = ?
If you want information for a given media entry, and you don't know what type it is, you'd have to join to all your subtype tables, knowing that only one such subtype table will match:
SELECT m.name, t.episode, v.release_date
FROM media AS m
LEFT OUTER JOIN tv_series AS t USING (media_id)
LEFT OUTER JOIN movies AS v USING (media_id)
WHERE m.media_id = ?
If the given media is a movie,then all columns in t.* will be NULL.
Consider using a main basic data table with tables extending off of it with specialized information.
Ex.
basic_data
id int,
name character varying(100),
description text,
url character varying(255)
tv_series
id int,
BDID int, --foreign key to basic_data
season,
episode
airing
movies
id int,
BDID int, --foreign key to basic_data
release_data
budget
What you are looking for is called 'disjoint subtypes' in the relational world. They are not supported in sql at the language level, but can be more or less implemented on top of sql.
You could create one table with the main fields plus a uid then extension tables with the same uid for each specific case. To query these like separate tables you could create views.
Using the disjoint subtype approach suggested by Bill Karwin, how would you do INSERTs and UPDATEs without having to do it in two steps?
Getting data, I can introduce a View that joins and selects based on specific media_type but AFAIK I cant update or insert into that view because it affects multiple tables (I am talking MS SQL Server here). Can this be done without doing two operations - and without a stored procedure, natually.
Thanks
Question is quite old but for modern postresql versions it's also worth considering using json/jsonb/hstore type.
For example:
create table some_table (
name character varying(100),
description text,
url character varying(255),
additional_data json
);