Data integrity when referencing many-to-many relationship in sql - sql

Consider the following tables:
db.quiz
- ID: int
- name: varchar(50)
db.quiz_device
- quiz_id: int (FK db.quiz.id)
- device_id: int (FK db.device.id)
db.device
- ID: int
- manufacturer: varchar(50)
- name: varchar(50)
- model: varchar(50)
db.quiz_responses
- ID: int
- quiz_id: int (FK db.quiz.id)
- device_id: int (FK db.device.id)
- score: int
The above represents a quiz which is getting initialized with a collection of devices. From the quiz, a subject rates each device with a score between 1 and 10, and the results are stored in quiz_responses.
The above database design has a data integrity problem because quiz_responses may reference devices that are not within the scope of quiz.
To me, I have a hard time finding alternative ways of designing this, so that the devices which can be referenced in quiz_responses only entail the devices that belong to the quiz_id FK in quiz_responses.
In this case, would this be an acceptable issue, or could this be approached in another way?

In the table db.quiz_device create a single PK column and make this the FK column in quiz_responses, rather than the 2 columns you have at the moment e.g.
db.quiz_device
id: int (PK)
quiz_id: int (FK db.quiz.id)
device_id: int (FK db.device.id)
quiz_responses
ID: int
quiz_device_id: int (FK db.quiz_device.id)
score: int

Related

How should I create an n-ary relationship?

After reading several articles on n-ary database relationships I'm still in the dark on some aspects of them.
I draw the ER diagram below myself and I purposedly used fake, made-up English words that cannot convey any semantics:
Does it mean that:
Each abacot kimes at most once with a gimble, and with many dords and wabes?
Similarly, each gimble kimes at most once with an abacot, and with many dords and wabes?
Each kiming relationship may include several dords and/or wabes?
Will I need three tables to represent this relationship, or one will suffice?
But above all, is it possible to generate a database schema with this diagram alone, without any extra explanations? The database exercises I see in books don't include anything else besides the diagram.
This is how I see it so far:
CREATE TABLE kiming (
kiming_id INT PRIMARY KEY NOT NULL,
abacot_id INT NOT NULL REFERENCES abacot (abacot_id),
gimble_id INT NOT NULL REFERENCES gimble (gimble_id),
UNIQUE (abacot_id), -- is this necessary?
UNIQUE (gimble_id) -- is this necessary?
);
CREATE TABLE kiming_wabe ( -- do I need this table?
kiming_id INT REFERENCES kiming (kiming_id),
wabe_id INT REFERENCES wabe (wabe_id)
);
CREATE TABLE kiming_dord ( -- do I need this table?
kiming_id INT REFERENCES kiming (kiming_id),
dord_id INT REFERENCES dord (dord_id)
);
To your question of is it possible to generate a database schema with this diagram alone" - the answer is NO.
The diagram is unclear. There is no way to know how the 1's and N's relate to each other. If all I had to go on was the diagram, I could argue for at least 6 different interpretations. The diagram doesn't use a recognizable scheme for representing relationships of this type, so it's all guesswork.
For understanding of you diagram one to one and one to many relationship solution as below.
Table schema you will change as required.
CREATE TABLE abacot (
abacot_id INT PRIMARY KEY NOT NULL,
abacot_details_columns varchar);
CREATE TABLE gimble (
gimble_id INT PRIMARY KEY NOT NULL,
gimble_details_columns varchar);
CREATE TABLE wabe (
wabe_id INT PRIMARY KEY NOT NULL,
wabe_details_columns varchar);
CREATE TABLE dord (
dord_id INT PRIMARY KEY NOT NULL,
dord_details_columns varchar);
CREATE TABLE kiming (
kiming_id INT PRIMARY KEY NOT NULL,
kiming_details_columns varchar
CREATE TABLE kiming_relationship_table (
kiming_id INT PRIMARY KEY NOT NULL,
abacot_id INT NOT NULL REFERENCES abacot (abacot_id),
gimble_id INT NOT NULL REFERENCES gimble (gimble_id),
UNIQUE (abacot_id), -- is this necessary? Yes
UNIQUE (gimble_id) , -- is this necessary? Yes
wabe_id INT REFERENCES wabe (wabe_id),
dord_id INT REFERENCES dord (dord_id)
);

Multiple inner joins in a query

Players{
Pid int primary key,
tid int not null references Teams,
name text not null,
age int not null
}
Teams{
tid int primary key,
name text not null,
location not null
}
Possessions{
id int primary key,
pid int not null references Players,
time int not null, //the time the possession started for a player
held int not null //for how much time he had the ball
}
I would like to create a view called Teampasses where I can select (passer,passee) as follows:Passer and passe must be from the same team and passes possession starting time equals to passes possession starting time +held (time he has the ball). What I have done so far is this:
SELECT x.name AS passer,y.name as Pasee
FROM player x
INNER JOIN player y ON x.tid=y.tid
INNER JOIN possesions p ON p.pid=x.pid AND p.pid=y.pid AND ...
in the ... section right of AND i would like to do something like x.time+x.held=y.time.How could i refer to there two?
I see an issue with your data:
Your Possessions table only has a single foreign key to the Players table for the passer. It needs to also include the Pid of the Passee. Otherwise, there's no way to filter out which player on the passer team is the Passee for a given Possession.
I would suggest changing the Possessions table as follows:
Possessions(
id int primary key,
pid_passer int not null references Players,
pid_passee int not null references Players,
time int not null, //the time the possession started for a player
held int not null //for how much time he had the ball
)
With this change, your data will work and the query becomes trivial.

How to update the nested tables in sql using gorm?

Here the code is written in Go. I am using two tables where one table has a foreign key that refers to the other table's primary key. Let's say I have a database as following struct defined:
type User struct{
ID uint `gorm:"primary_key;column:id"`
Name string `gorm:"column:name"`
Place place
PlaceID
}
type Place struct{
ID uint `gorm:"primary_key;column:id"`
Name string `gorm:"column:name"`
Pincode uint `gorm:"column:pincode"`
}
And the sql schema is:
create table place(
id int(20) NOT NULL AUTO_INCREMENT,
name varchar(100) NOT NULL,
pincode uint(20) NOT NULL,
PRIMARY KEY (id),
)
create table user(
id int(20) NOT NULL AUTO_INCREMENT,
name varchar(100) NOT NULL,
place_id uint(20) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (place_id) REFERENCES place(id)
)
Now while inserting in user by gorm as:
place := Place{Name:"new delhi",Pincode:1234}
user := User{Name: "sam", Age: 15, Place: place}
err = db.Debug().Create(&user).Error
//It inserts to both user and place table in mysql
//now while updating to name in user table as Samuel and place as
//following
place := Place{Name:"mumbai",Pincode:1234}
err = db.Debug().Model(&User{}).Where("id =?",
1,).Update(&user{Name:"Samuel",Place:place}).Error
It updates the row in user table but creates a new row in place table.But it should update the matching row in place table and not create a new one
Is there any way to do it? Here I am not using auto migrate function to create db tables.
The answer to your question should be sought in a relations or Association Mode.
The example below shows how to add new associations for many to many, has many, replace current associations for has one, belongs to
db.Model(&user).Association("Place").Append(Place{Name:"mumbai",Pincode:1234})
Or you can replace current associations with new ones:
db.Model(&user).Association("Place").Replace(Place{Name:"mumbai",Pincode:1234},Place{Name:"new delhi",Pincode:1234})
Probably It's creating a new row because you didn't set the ID on Place{Name:"mumbai",Pincode:1234}.

Create Script to Update Record on the basis of Condition

Table Structure:
1) Campaign
Camp_Code int - Primary Key
AssignTo int
CreatedBy int
Status int
2) Company
CompanyID int - Primary Key
Name varchar(100)
Camp_Code int - Foreign Key
AssignTo int
One Campaign has many Company
Now I need to create script to update the Company Table
I need to update the AssignTo field of the Company Table.
I need to update only those Company whose Camp_Code Status is 0.
Update of the AssignTo(Company) is based on the Camp_Code(Company) and Camp_Code(Campaign)
Here you can see if the AssignTo(Campaign) field is empty then it takes value of the CreatedBy(Campaign) field.
Please help me...
this should work:
UPDATE co SET co.assignto=COALESCE(ca.AssignTo, ca.CreatedBy)
FROM company co
JOIN (select * FROM campaign WHERE status=0) ca ON(co.camp_code=ca.camp_code)

SQL - Create table in SQL

Please guide me if I'm on right track.
I'm trying to create database schema for Mobile Bill for a person X and how to define PK, FK for the table Bill_Detail_Lines.
Here are the assumptions:
Every customer will have a unique relationship number.
Bill_no will be unique as it is generated every month.
X can call to the same mobile no every month.
Account_no is associated with every mobile no and it doesn't change.
Schema:
table: Bill_Headers
Relationship_no - int, NOT NULL , PK
Bill_no - int, NOT NULL , PK
Bill_date - varchar(255), NOT NULL
Bill_charges - int, NOT NULL
table: Bill_Detail_Lines
Account_no - int, NOT NULL
Bill_no - int, NOT NULL , FK
Relationship_no - int, NOT NULL, FK
Phone_no - int, NOT NULL
Total_charges - int
table: Customers
Relationship_no - int, NOT NULL, PK
Customer_name - varchar(255)
Address_line_1 - varchar(255)
Address_line_2 - varchar(255)
Address_line_3 - varchar(255)
City - varchar(255)
State - varchar(255)
Country - varchar(255)
I would recommend having a primary key for Bill_Detail_Lines. If each line represents a total of all calls made to a given number, then the natural PK seems to be (Relationship_no, Bill_no, Phone_no), or maybe (Relationship_no, Bill_no, Account_no).
If each line instead represents a single call, then I would probably add a Line_no column and make the PK (Relationship_no, Bill_no, Line_no).
Yes, as for me, everything looks good.
I have to disagree, there's a couple of 'standards' which aren't being followed. Yes the design looks ok, but the naming convention isn't appropriate.
Firstly, table names should be singular (many people will disagree with this).
If you have a single int, PK on a table, the standard is to call it 'ID', thus you have "SELECT Customer.ID FROM Customer" - for instance. You also then fully qualify the FK columns, for instance: CustomerID on Bill_Headers instead of Relationship_no which you then have to check in the table definition to remember what it's related to.
Something I also always keep in mind, is to make the column header as clear and short as possible without obfuscating the name. For instance, "Bill_charges" on Bill_Headers could just be "Charges", as you're already on the Bill_Header(s) (<- damn that 's'), same goes for Date, but date could be a bit more descriptive, CreatedDate, LastUpdatedDate, etc...
Lastly, beware of hard-coding multiple columns where one would suffice, same other way around. Specifically I'm talking about:
Address_line_1 - varchar(255)
Address_line_2 - varchar(255)
Address_line_3 - varchar(255)
This will lead to headaches later. SQL does have the capability to store new line characters in a string, thus combining them to one "Address - varchar(8000)" would be easiest. Ideally this would be in a separate table, call it Customer_Address with int "CustomerID - int PK FK" column where you can enter specific information.
Remember, these are just suggestions as there's no single way of database design that everyone SHOULD follow. These are best practices, at the end of the day it's your decision to make.
There are a few mistakes:
Realtionship_no and Bill_no are int. Make sure that the entries are within the range of integer. It is better to take them as varchar() or char()
Bill_date should be in data type Date
In table Bill_Detail_Lines also, it is better to have Account_no as varchar() or char() because of the long account no. And the same goes with Phone_no.
Your Customers table is all fine except that you have taken varchar() size as 255 for City State and Country which is too large. You can work with smaller size also.