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.
Related
I have a question regarding to primary key for Oracle Table with Period.
I have created two tables like following:
create table el_temporal_try( -- Parent Table
id number(10) not null,
ColumnA varchar(10),
constraint el_temporal_try_pk primary key (id),
period for valid_period
);
create table el_temporal_try_son( -- Son Table
id number(10) not null,
ColumnA varchar(10),
parent_id number(10),
constraint el_temporal_try_FY foreign key (parent_id) references el_temporal_try(id),
period for valid_period
);
This script gone through successfully. However I have problem with inserting data:
I have executed following two insert statements into the parent table:
1st: statement
insert into el_temporal_try
(id, columnA,valid_period_start, valid_period_end)
values
(1,'A',sysdate - 10, sysdate - 9);
Result:
1 row inserted.
2nd: statement
insert into el_temporal_try
(id, columnA,valid_period_start, valid_period_end)
values
(1,'B',sysdate - 8, sysdate - 7);
Result
ORA-00001: unique constraint (PBSVW.EL_TEMPORAL_TRY_PK) violated
I understand it is because of the "ID" column. However, my issues because this two rows are for a different period, should it be allowed?
I was intended to use this period for feature to capture the change history of a record as an alternative to flashback. However, does it means that I should not use primary key at this situation?
Thanks in advance!
The problem is related to the id column like you said. it's not possible to add the registry because the primary key is unique, then your second insert statement references the same ID from the first. You need to change the ID always you insert a line.
On Oracle 12c, you can use the identity like this link.
https://www.oracletutorial.com/oracle-basics/oracle-identity-column/
in another version, you can use sequence and trigger to do this.
https://chartio.com/resources/tutorials/how-to-define-an-auto-increment-primary-key-in-oracle/
Thanks for everyone's help on this. This most likely means I cannot use Primary Key/Foreign Key to maintain the referential integrity between the parent and son for my situation within a particular timestamp, but I have to go for something else.
Thanks a lot!
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.
I am piggy backing off this question regarding creating a junction/linking table. It is clear how to create a junction table, but I am concerned about how to fill the junction table with data. What is the simplest and/or best method for filling out the junction table (movie_writer_junction) with data between two other tables (movie, writer)
CREATE TABLE movie
(
movie_id INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
movie_name NVARCHAR(100),
title_date DATE
);
CREATE TABLE writer
(
writer_id INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
writer_name NVARCHAR(100),
birth_date DATE
);
INSERT INTO movie
VALUES ('Batman', '2015-12-12'), ('Robin', '2016-12-12'),
('Charzard, the movie', '2018-12-12')
INSERT INTO writer
VALUES ('Christopher', '1978-12-12'), ('Craig', '1989-12-12'),
('Ash', '1934-12-12')
CREATE TABLE movie_writer_junction
(
movie_id INT,
writer_id INT,
CONSTRAINT movie_writer_pk
PRIMARY KEY(movie_id, writer_id),
CONSTRAINT movie_id_fk
FOREIGN KEY(movie_id) REFERENCES movie(movie_id),
CONSTRAINT writer_fk
FOREIGN KEY(writer_id) REFERENCES writer(writer_id)
);
The final junction table is currently empty. This is a simple example, and you can manually fill the data into the junction table, but if I have two tables with millions of rows, how is something like this completed?
Hi I'm guessing this relates to the fact that you can't rely on the Identity Columns being the same in different regions.
You can write your inserts as a cross join from the 2 src tables
Insert junc_table (writer_id, movie_id)
Select writer_id , movie_id
from writer
CROSS Join
movie
where writer_name = 'Tolkien' and movie_name = 'Lord of the Ring'
This way you always get the correct Surrogate Key (the identity) from both tables.
Its pretty easy to generate a SQL statement for all your existing junction combinations using a bit of Dynamic SQL
Another Approach is to Use SET IDENTITY_INSERT ON - but this needs to be done when loading the 2 other tables and that ship may already have sailed!
I Have table three tables:
The first one is emps:
create table emps (id number primary key , name nvarchar2(20));
The second one is cars:
create table cars (id number primary key , car_name varchar2(20));
The third one is accounts:
create table accounts (acc_id number primary key, woner_table nvarchar2(20) ,
woner_id number references emps(id) references cars(id));
Now I Have these values for selected tables:
Emps:
ID Name
-------------------
1 Ali
2 Ahmed
Cars:
ID Name
------------------------
107 Camery 2016
108 Ford 2012
I Want to
Insert values in accounts table so its data should be like this:
Accounts:
Acc_no Woner_Table Woner_ID
------------------------------------------
11013 EMPS 1
12010 CARS 107
I tried to perform this SQL statement:
Insert into accounts (acc_id , woner_table , woner_id) values (11013,'EMPS',1);
BUT I get this error:
ERROR at line 1:
ORA-02291: integrity constraint (HR.SYS_C0016548) violated - parent key not found.
This error occurs because the value of woner_id column doesn't exist in cars table.
My work require link tables in this way.
How Can I Solve This Problem Please ?!..
Mean: How can I reference tables in previous way and Insert values without this problem ?..
One-of relationships are tricky in SQL. With your data structure here is one possibility:
create table accounts (
acc_id number primary key,
emp_id number references emps(id),
car_id number references car(id),
id as (coalesce(emp_id, car_id)),
woner_table as (case when emp_id is not null then 'Emps'
when car_id is not null then 'Cars'
end),
constraint chk_accounts_car_emp check (emp_id is null or car_id is null)
);
You can fetch the id in a select. However, for the insert, you need to be explicit:
Insert into accounts (acc_id , emp_id)
values (11013, 1);
Note: Earlier versions of Oracle do not support virtual columns, but you can do almost the same thing using a view.
Your approach should be changed such that your Account table contains two foreign key fields - one for each foreign table. Like this:
create table accounts (acc_id number primary key,
empsId number references emps(id),
carsId number references cars(id));
The easiest, most straightforward method to do this is as STLDeveloper says, add additional FK columns, one for each table. This also bring along with it the benefit of the database being able to enforce Referential Integrity.
BUT, if you choose not to do, then the next option is to use one FK column for the the FK values and a second column to indicate what table the value refers to. This keeps the number of columns small = 2 max, regardless of number of tables with FKs. But, this significantly increases the programming burden for the application logic and/or PL/SQL, SQL. And, of course, you completely lose Database enforcement of RI.
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);