Foreign key is needed for inner join in SQL? - sql

INSERT INTO customers (ID, NAME, AGE, ADDRESS, SALARY)
VALUES(3, 'sin', 21, 'bangalore', 10000);
INSERT INTO orders (orderid, orderno)
VALUES (3, 21);
Here ID is the primary key in the customer table, orderid is the primary key in the orders table.
I would like to know whether it is mandatory to add id as foreign key in orders table for performing SQL join?

It is not necessary to establish a foreign key in order to perform an inner join of the customers and orders table. However, the question arises of what the significance of such a join operation would be without a foreign key.
Presumably the goal is to model some sort of relationship between customers and orders. Assuming the attributes listed comprise all of the attributes in the two tables, there is nothing establishing a relationship between customers and orders in the way the tables are defined. Adding a customerID field as a foreign key in the orders table would establish that relationship. Then, an inner join on the condition customers.ID = orders.customerID would associate the order information with the appropriate customer's information in the joined table.

My thought here that when you asking whether FK is needed or not, you accept by default that both working within the same domain, and this is not a valid assumption, in brief
The inner join is used with the reading (query) of data, whereas FK
exists to maintain the integrity of data during a different kind of operations such as insert, update and delete.
In my opinion, the correct answer should be that both FK and inner join are not relevant.
I will use the below tables to explain the difference between both
Customers
| id | name |
|:------------|---------:|
| 1 | Gabriel |
| 2 | John |
| 3 | Smith |
Orders
| order_id |customer_id|
|:-----------|---------: |
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
Inner Join,
is used during query for example according to the above, let's say you want to query all orders made by a specific customer.
select * from customers, orders
where customer.id=orders.customer_id
and customer.id=2
according to our tables, you will end up with one order number (4) for the customer (John)
Foreign Key
While the inner join used during the query, the Foreign Key is used to apply policies over the major DML operations (Insert, update and delete).
below are examples of operations that will fail for violating the FK constraint
Insert into orders(order_id,customer_id) values(5,7)
this operation will fail because no customer exists with id (7) in the Customer table, the same will apply for the update operation.
Also if the FK enabled the On delete cascade or On update cascade
this will delete or update child rows when trying to delete or update the master table, example deleting the customer Gabriel will delete orders 1,2 and 3.

Related

SQL database relationships: correct implementation of Junction Model in manyToMany relationship?

I have two database tables "Users" and "Transactions" with many to many relationship between them. I have created a Junction Model which will have two foreign key columns (UserId, TransactionId) and will keep track of the associations. The Transaction table has two columns where I keep track of who the sender is and who the recipient is (senderAccount, recipientAccount).
Question 1: since each Transaction belongs to two users which are the sender and recipient, do I also need to specify both senderId and recipientId inside the junction model instead of just userId?
Note: my confusion is from the two foreign key columns(UserId and TransactionId) inside the junction model. I understand that there is only one transaction and you can reference that transaction by its id in the junction model, but each transaction is also owned by two users (sender and recipient) shouldn't we reference both of the users inside the junction model?
Question 2: if my analogy up here is correct, how would you reference both senderId and recipientId inside the junction model?
Question 3: if my analogy up here is incorrect, please help me understand how you would go about referencing both users in the junction model.
Users table
id | username |
—--+----------+
1 | ijiej33 |
Transactions table
id | transactionId | senderAccount | recipientAccount | Amount |
—--+---------------+---------------+------------------+--------+
1 | ijiej33 | A | B | 100 |
userTransaction table (junction model)
userId | TransactionId |
-------+---------------+
| |
As I explained as a comment in your question from yesterday, you do not have a many-to-many relationship between transactions and users. You have two many-to-one relationships from transactions to users. You therefore do not need a join table.
Model it thus:
create table users (
user_id serial primary key,
user_name text not null unique
);
create table transaction (
transaction_id serial primary key,
sender_account int not null references users(user_id),
recipient_account int not null references users(user_id),
amount numeric
);

Validate whether value in one table is the same as in related table - performance

Let's say I have two tables and I'm doing all the operations in .NET Core 2 Web API.
Table A:
Id,
SomeValue,
TeamName
Table B:
Id,
Fk_Id_a (references Id in table A),
OtherValue,
TeamName
I can add and get records from table B indepedently.
But for every record in Table B TeamName has to be the same as for it's corresponidng Fk_Id_a in Table A.
Assume these values comes in:
{
"Fk_Id_a": 3,
"SomeValue": "test val",
"TeamName": "Super team"
}
Which way would be better to check it in terms of performance? 1ST way requires two connections, when 2nd requires storing some extra keys etc.
1ST WAY:
get record from Table A for Fk_Id_a (3),
check if TeamName is the same as in coming request (Super team),
do the rest of the logic
2ND WAY:
using compound foreign keys and indexes:
TableA has alternate unique key (Id, TeamName)
TableB has foreign compound key (Fk_Id_a, TeamName) that references TableA (Id, TeamName)
SQL SCRIPT TO SHOW:
ALTER TABLE Observation
ADD UNIQUE (Id, PowelTeamId)
GO
ALTER TABLE ObservationPicturesId
ADD FOREIGN KEY(ObservationId, PowelTeamId)
REFERENCES Observation(Id, PowelTeamId)
ON DELETE CASCADE
ON UPDATE CASCADE
EDIT: Simple example how the tables might look like. TeamName has to be valid for FK referenced value in Table A.
Table A
ID | ObservationTitle | TeamName
---------------------------------------
1 | Fire damage | CX_team
2 | Water damage | CX_team
3 | Wind damage | Dd_WP3
Table B
ID | PictureId | AddedBy | TeamName | TableA_ID_FK
-----------------------------------------------------
1 | Fire | James | CX_team | 1
2 | Water | Andrew | CX_team | 1
3 | Wind | John | Dd_WP3 | 3
Performance wise, the 2nd option would be faster because there is no comparison to check (the foreign key will force that they match when inserting, updating or deleting) when selecting the rows from the table. It would also make a unique index on table A.
That being said, there is something very fishy about the structure you mention. First of all why is the TeamName repeated in table B? If a row in table B is "valid" only when the TeamName match, then you should enforce that no row should be inserted with a different TeamName, throught the ID foreign key (and not actually storing the TeamName value). If there are records on table B that represent another thing rather than the entity that is linked to table A then you should split it onto another table or just update the foreign key column when the team matches and not always.
The issue is that you are using a foreign key as a partial link, making the relationship valid only when an additional condition is true.

How to associate two tables based on a unique id

I have two tables I want to join in SQL Server.
One houses call data and has a unique id Login_ID. This table does not contain the employees name.
The other table does not have a unique id for employees.
What I need to do is join these two tables so I can see call data and ticket data simultaneously by employee.
Unfortunately, there is no correlating column for Login_ID in the ticket table to link employee data.
Example of call data table:
Login_ID | Calls | CallTime | Date |
00000001 | 34 | 349874 | 030317 |
Example of ticket table:
Name | Ticket_Num | Date |
Some Emp | 5456465434 | 030317 |
So what happens is: anytime someone changes their name, they basically have a new ID in this table. It's awful.
I only need the data from around 18 employees.
My question is: how can I associate the Login_ID with the ticket table?
Hopefully I made this clear enough!
You should to store the association using what is known as a Foreign Key. This will ensure the integrity of the relationships between your data and can help optimize your queries when you are trying to pull associated data from different tables.
A FOREIGN KEY is a key used to link two tables together.
A FOREIGN KEY is a field (or collection of fields) in one table that
refers to the PRIMARY KEY in another table.
The table containing the foreign key is called the child table, and
the table containing the candidate key is called the referenced or
parent table.
You get query associated date using a join.
If you have a 1:1 relationship you add Login_ID as a field to your ticket table and you can join your table on Login.Login_ID = Tickets.Login_Id.
Alter Table Tickets
Add Login_ID int not null Constraint "FK_Tickets_LoginId" References Tickets(Login_Id)
// USAGE:
Select * from Logins Join Tickets on Logins.Login_ID=Tickets.Login_Id where Login_ID=#LoginId
If you can't modify either table then you can create a new table, perhaps Logins2Tickets which will contain two fields Login_ID and Ticket_Num
You can then join your Logins to Logins2Tickets on Login.Login_ID = Tickets.Login_Id and join Logins2Tickets to Tickets on Logins2Tickets.Ticket_Num = Tickets.Ticket_Num
Create Table Logins2Tickets
(
Login_ID int not null constraint "FK_Logins2Tickets_Login_ID" References Logins(Login_Id)
Ticket_Num bigint not null constraint "FK_Logins2Tickets_Ticket_Num" References Tickets(_Login_ID)
)
// USAGE:
Select *
From
Logins l Join Logins2Tickets lt
on l.Login_ID=lt.Login_ID
Join Tickets t
on lt.Ticket_Num=t.Ticket_Num
WHERE Login_ID=#LoginId

Can a foreign key refer to a primary key in the same table?

I just think that the answer is false because the foreign key doesn't have uniqueness property.
But some people said that it can be in case of self joining the table.
I am new to SQL. If its true please explain how and why?
Employee table
| e_id | e_name | e_sala | d_id |
|---- |------- |----- |--------|
| 1 | Tom | 50K | A |
| 2 | Billy | 15K | A |
| 3 | Bucky | 15K | B |
department table
| d_id | d_name |
|---- |------- |
| A | XXX |
| B | YYY |
Now, d_id is foreign key so how it can be a primary key. And explain something about join. What is its use?
I think the question is a bit confusing.
If you mean "can foreign key 'refer' to a primary key in the same table?", the answer is a firm yes as some replied. For example, in an employee table, a row for an employee may have a column for storing manager's employee number where the manager is also an employee and hence will have a row in the table like a row of any other employee.
If you mean "can column(or set of columns) be a primary key as well as a foreign key in the same table?", the answer, in my view, is a no; it seems meaningless. However, the following definition succeeds in SQL Server!
create table t1(c1 int not null primary key foreign key references t1(c1))
But I think it is meaningless to have such a constraint unless somebody comes up with a practical example.
AmanS, in your example d_id in no circumstance can be a primary key in Employee table. A table can have only one primary key. I hope this clears your doubt. d_id is/can be a primary key only in department table.
This may be a good explanation example
CREATE TABLE employees (
id INTEGER NOT NULL PRIMARY KEY,
managerId INTEGER REFERENCES employees(id),
name VARCHAR(30) NOT NULL
);
INSERT INTO employees(id, managerId, name) VALUES(1, NULL, 'John');
INSERT INTO employees(id, managerId, name) VALUES(2, 1, 'Mike');
-- Explanation:
-- In this example.
-- John is Mike's manager. Mike does not manage anyone.
-- Mike is the only employee who does not manage anyone.
Sure, why not? Let's say you have a Person table, with id, name, age, and parent_id, where parent_id is a foreign key to the same table. You wouldn't need to normalize the Person table to Parent and Child tables, that would be overkill.
Person
| id | name | age | parent_id |
|----|-------|-----|-----------|
| 1 | Tom | 50 | null |
| 2 | Billy | 15 | 1 |
Something like this.
I suppose to maintain consistency, there would need to be at least 1 null value for parent_id, though. The one "alpha male" row.
EDIT: As the comments show, Sam found a good reason not to do this. It seems that in MySQL when you attempt to make edits to the primary key, even if you specify CASCADE ON UPDATE it won’t propagate the edit properly. Although primary keys are (usually) off-limits to editing in production, it is nevertheless a limitation not to be ignored. Thus I change my answer to:- you should probably avoid this practice unless you have pretty tight control over the production system (and can guarantee no one will implement a control that edits the PKs). I haven't tested it outside of MySQL.
Eg: n sub-category level for categories .Below table primary-key id is referred by foreign-key sub_category_id
A good example of using ids of other rows in the same table as foreign keys is nested lists.
Deleting a row that has children (i.e., rows, which refer to parent's id), which also have children (i.e., referencing ids of children) will delete a cascade of rows.
This will save a lot of pain (and a lot of code of what to do with orphans - i.e., rows, that refer to non-existing ids).
Other answers have given clear enough examples of a record referencing another record in the same table.
There are even valid use cases for a record referencing itself in the same table. For example, a point of sale system accepting many tenders may need to know which tender to use for change when the payment is not the exact value of the sale. For many tenders that's the same tender, for others that's domestic cash, for yet other tenders, no form of change is allowed.
All this can be pretty elegantly represented with a single tender attribute which is a foreign key referencing the primary key of the same table, and whose values sometimes match the respective primary key of same record. In this example, the absence of value (also known as NULL value) might be needed to represent an unrelated meaning: this tender can only be used at its full value.
Popular relational database management systems support this use case smoothly.
Take-aways:
When inserting a record, the foreign key reference is verified to be present after the insert, rather than before the insert.
When inserting multiple records with a single statement, the order in which the records are inserted matters. The constraints are checked for each record separately.
Certain other data patterns, such as those involving circular dependences on record level going through two or more tables, cannot be purely inserted at all, or at least not with all the foreign keys enabled, and they have to be established using a combination of inserts and updates (if they are truly necessary).
Adding to the answer by #mysagar the way to do the same in MySQL is demonstrated below -
CREATE TABLE t1 (
-> c1 INT NOT NULL,
-> PRIMARY KEY (c1),
-> CONSTRAINT fk FOREIGN KEY (c1)
-> REFERENCES t1 (c1)
-> ON UPDATE RESTRICT
-> ON DELETE RESTRICT
-> );
would give error -
ERROR 1822 (HY000): Failed to add the foreign key constraint. Missing index for constraint 'fk' in the referenced table 't1'
The correct way to do it is -
CREATE TABLE t1 (
-> c1 INT NOT NULL,
-> PRIMARY KEY (c1),
-> KEY i (c1),
-> CONSTRAINT fk FOREIGN KEY (c1)
-> REFERENCES t1 (c1)
-> ON UPDATE RESTRICT
-> ON DELETE RESTRICT
-> );
One practical utility I can think of is a quick-fix to ensure that after a value is entered in the PRIMARY KEY column, it can neither be updated, nor deleted.
For example, over here let's populate table t1 -
INSERT INTO t1 (c1) VALUES
-> (1),
-> (2),
-> (3),
-> (4),
-> (5);
SELECT * FROM t1;
+----+
| c1 |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
Now, let's try updating row1 -
UPDATE t1
-> SET c1 = 6 WHERE c1 = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`constraints`.`t1`, CONSTRAINT `fk` FOREIGN KEY (`c1`) REFERENCES `t1` (`c1`) ON DELETE RESTRICT ON UPDATE RESTRICT)
Now, let's try deleting row1 -
DELETE FROM t1
-> WHERE c1 = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`constraints`.`t1`, CONSTRAINT `fk` FOREIGN KEY (`c1`) REFERENCES `t1` (`c1`) ON DELETE RESTRICT ON UPDATE RESTRICT)

Database structure: Customers buy different items

I have a table which stores all item information and its id. Now I want to create an table with all customers and log which item who bought. What is the best solution for this? I guess it is not very efficient if store it like this:
|customer_id | username | password | boughtproducts |
| 1 | herbert |123 |productid1,pid2...|
How would you do it?
A simpler way to deal with this situation is the following:
Table Customer:
customer_id | username | password
Table Product:
product_id | productName | ...
Table Sales:
sale_id | customer_id | product_id | Time of sale
This way, using the table 'Sales', you will store all the sales of every customer and product.
The customer_id in 'Sales' is a foreign key from 'Customer' table, and product_id in 'Sales' is a foreign key from 'Product' table.
I hope this answered your question
There are numerous examples of this type of schema available on the web.
But in summary your DB may take the form of...
Customer table : One customer can have many..
Order table : One order can have many..
OrderLine table : One orderline will be related to one...
Product table. (And one Product will be related to may OrderLines)
So OrderLine will contain a ProductID and Quantity. You can then JOIN tables and make a full Order.
I would actually go with 2 more tables. One for Customer and then a second for Products they bought Like So:
Customer
CustomerID|Username|Password
PUrchases:
CustomerID|ProductID|Date| etc
have one Customers Table // store details of the customers
have once Products Table // store details of the products
have one Customers_products Table
|primary_key|customer_id | product_id |
| | 1 | 1 |
| | 1 | 2 |
There is Many to Many Relationship between Customers and Products. One customer can buy many products, similarly one product can be bought by many customers. So standard way to implement many to many relationships, is to have one more table, and this new table will contain primary keys from both tables.
Primary Key can be AutoIncremented, or a composite key of both the foreign keys.