How to insert values into a junction/linking table in SQL Server? - sql

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!

Related

Best practice for verifying correctness of data in MS SQL

We have multiple tables with different data (for example masses, heights, widths, ...) that needs to be verified by employees. To keep track of already verified data, we are thinking about designing a following table:
TableName varchar
ColumnName varchar
ItemID varchar
VerifiedBy varchar
VerificationDate date
This table links the different product id's, tables and columns that will be verified, for example:
Table dbo.Chairs
Column dbo.Chairs.Mass
ItemId 203
VerifiedBy xy
VerificationDate 10.09.2020
While creating foreign keys, we were able to link the ItemID to the central ProductsID-Table. We wanted to create two more foreign keys for database tables and columns. We were unable to do this, since "sys.tables" and "INFORMATION_SCHEMA.COLUMNS" are views.
How can I create the foreign keys to the availible database tables/columns?
Is there better way how to do such a data verification?
Thanks.
You can add a CHECK constraint to verify that the correctness of the data which is inserted/updated in the columns TableName and ColumnName, like this:
CREATE TABLE Products (
ItemID VARCHAR(10) PRIMARY KEY,
ItemName NVARCHAR(50) UNIQUE
)
CREATE TABLE Chairs (
ItemID VARCHAR(10) PRIMARY KEY,
FOREIGN KEY (ItemID) REFERENCES dbo.Products,
Legs TINYINT NOT NULL
)
CREATE TABLE Sofas (
ItemID VARCHAR(10) PRIMARY KEY,
FOREIGN KEY (ItemID) REFERENCES dbo.Products,
Extendable BIT NOT NULL
)
CREATE TABLE Verifications (
TableName sysname NOT NULL,
ColumnName sysname NOT NULL,
ItemID VARCHAR(10) REFERENCES dbo.Products,
VerifiedBy varchar(30) NOT NULL,
VerificationDate date NOT NULL,
CHECK (COLUMNPROPERTY(OBJECT_ID(TableName),ColumnName,'ColumnId') IS NOT NULL)
)
You need to grant VIEW DEFINITION on the tables to the users which have rights to insert/update the data.
This will not entirely prevent wrong data, because the check constraints will not be verified when you drop a table or a column.
However, I don't think this is necessarily a good idea. A better (and more conventional) way would be to add the VerifiedBy and VerificationDate to the Products table (if you can force the user to verify all the properties at once) or create separate columns regarding each verified column (for example LegsVerifiedBy and LegsVerificationDate in the Chairs table, ExtendableVerifiedBy and ExtendableVerificationDate in the Sofas table, etc), if the verification really needs to be done separately for each column.

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.

Creating relation between tables in Movie Database

I have created a movie database that contain following tables :
1.Film
2.People
3.Genres
4.Role
5.Users
Here is my sql
create table Film ( id INT(30),title varchar(30),images varchar(30)
primary key (id));
create table people(id INT(30),Fname varchar(30),Lname varchar(30),
primary key (id));
create table Role(id INT(30), name varchar(30),
primary key(id));
i want create relation between Film,People and Role table.SO my Question is do i need to create a table to make relation between those table and is it necessary to use auto_increment for id column?
You'd want to create some tables like:
FilmRole( FilmId INT, RoleId INT) these 2 columns would make your PK and they are also FK's to their
FilmPeople (FilmId INT, PeopleId INT) respective source tables.
FilmUsers( FilmId INT, UserId INT)
You could add a single IDENTITY (for SQL Server for example) column to each table if you wanted but in this particular case a 2 column PK is adequate as these tables simply point to other records.
You need to alter your table and add in a foreign key (Primary key in one table and attribute in another). Examples how to do it here! http://www.w3schools.com/sql/sql_foreignkey.asp
do i need to create a table to make relation between those table ?
YES ! to enforce Referential integrity read this
is it necessary to use auto_increment for id column?
Depends but it is most prefered way of creating a PK on a table

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.

SQL - Field Grouping and temporary data restructruing

I would like to apologize first about my title, because I understand it may be technically incorrect
I currently have a database with multiple tables, 4 of them are relevant in this example.
FORMS
FIELDS
ENTRIES
VALUES
Below is a shortened version of the tables
Create table Form_Master
(
form_id int identity primary key ,
form_name varchar(255) ,
form_description varchar(255),
form_create_date date ,
)
Create table Field_Master
(field_id int identity primary key,
form_ID int foreign key references Form_Master(form_id),
field_name varchar(255),
type_ID int
)
Create table Entry_Master
(
entry_id int identity primary key,
entry_date date,
form_id int foreign key references Form_Master(form_id),
)
Create table Value_Master
(
value_id int identity primary key,
value varchar(255),
field_id int foreign key references Field_Master(field_id),
entry_id int foreign key references Entry_Master(entry_id),
)
The purpose of these tables is to create a dynamic method of capturing and retrieving information - a form is a table, a field is a column, and entry is a row and a value is a cell
Currently when I am retrieving information from a form, I create a temporary table, with columns as such in the field_master, then select all entries linked to the form, and the values linked to those entries, and insert them into the temporary table I have just created.
The reason for the temporary table is to restructure the data into an organised format and display it in a DataGridView.
My problem is one of performance, creating the table as mentioned above is becoming slower as forms exceed fields > 20 or entries linked to a form exceeds > 100
My questions are:
Is there a way to select the data directly from field_master in the format of the temporary table mentioned above?
Do you think I should re-think my database design?
Is there an easier method to do what I am trying to do?
Any input will be appreciated, I do know how to use Google, however in this instance I am not sure what exactly to look for, so even a keyword would be nice.