Two foreign keys reference the primary key of another table - sql

So I have two tables
Person(personID, first_name, last_name);
Relation(relationID, child_personID, parent_personID);
personID and relationID are both primary keys. child_personID and parent_personID are both foreign keys.
I want to make a query so I have the first names and last names of both the child and parent.
child.first_name child.last_name and parent.first_name, parent.last_name

One way to go about this is using joins and table aliases. Something like this:
select
child.first_name,
child.last_name,
parent.first_name,
parent.last_name
from relation r
join person child on r.child_personID = child.id
join person parent on r.parent_personID = parent.id

Related

How to delete records from two different tables that are linked with FK? SQL

I have two tables City and Buildings in my database. They are linked with city_number that is Primary Key in City table and Foreign Key in Buildings table. If user wants to delete record from City table I want to remove any records from the Buildings table that is tied to that City. I use unique auto incremented id passed through the argument to remove these records. My SQL Query looks like this:
DELETE C.*, B.*
FROM City AS C
INNER JOIN Buildings AS B
ON C.c_number = B.b_district
WHERE D.c_id = 'some id example: 107';
Query above won't work sicne SQL allow only records from one table to be removed with INNER JOIN so i will have to use two separate DELETE statements like this:
DELETE
FROM City
WHERE c_id = '107'
DELETE
FROM Buildings
WHERE b_city = 'city that is tied to unique id 107'
My question is, what is the best practice to remove records that are tied in two tables? Since I have to use two separate SQL statements, should I pass City and then delete record(s) from Buildings table? or Should I create another query that will pull City from City table based on unique id and then remove record(s) from Buildings? If anyone knows better way to do this please let me know.
I believe the easiest way to accomplish your goal would be to set up your foreign key with ON DELETE CASCADE. That way, whenever a row in the parent table is deleted, any related rows in the child table will be deleted automatically.
Here is an example of a way to alter a table in order to create a foreign key with ON DELETE CASCADE:
ALTER TABLE child_table
ADD CONSTRAINT fk_name
FOREIGN KEY (child_col1, child_col2, ... child_col_n)
REFERENCES parent_table (parent_col1, parent_col2, ... parent_col_n)
ON DELETE CASCADE;
In your case, the child table would be Buildings and the parent table would be City. It sounds like you would have just city_number for the column. You'll have to fill in the name of your foreign key.
Like Shannon mentioned, you can use ON DELETE CASCADE to delete data from parent and child tables.
Here is a working example:
http://sqlfiddle.com/#!18/f5860/10
Without writing out the code, here's what I would do:
Select all the ids to be deleted for buildings belonging to a city
Delete all the buildings
Delete the city
Put it in a stored procedure
Re-usable, self-contained, and clear.
This is a violation of SRP however, let me know if you care about that and I'll post a SRP based SQL solution.

A query with primary key field used twice

In my database I have two tables:
relationship table:
organization_id_first, organization_id_second, relationship_type
organization table:
primary key = org_id ; org_id, org_name, ...
How would I be able to join the organization table so that I could get the org_name for both organizations that have an entry in the relationship table? I don't think I can join on the same primary key. Would I have to do a subquery of some sort?
Thanks!
This is how i would do it in T-SQL ... just join it twice and make two different object
select or1.org_name, or2.org_name, rel.relationship_type from relationship rel
join organization or1 on rel.organization_id_first = or1.org_id
join organization or2 on rel.organization_id_second = or2.org_id

SQL parent table Childtable in one to many relationship

I have the following two schemas for two tables
create table My_contacts
(
Contact_ID, last name, first name, email, phone, profession_ID
)
Create table Profession
(
Profession_ID, Profession Name
)
The relationship between tables profession and My_contact and is one-to-many.
I need a fast way to decide which one is parent table and which one is child table, so my assumption is that because in the table My-Contacts has the foreign key profession_ID, it is the child table. (Based on primary key belongs to parent table, foreign key is in child table.)
However, I read the book Headfirst SQL, page P311. it says
we moved the profession column into a new child table, and change the profession column in the parent table into foreign key profession_ID"
according to the above, the book means the profession table is the child table, and the my_contact table is the parent table.
I have tried to figure out this conflict, but could not.

Designing 1:1 and 1:m relationships in SQL Server

In SQL Server 2008, how does one design a 1:1 and 1:m relationship?
Any relationship requires that the "parent" table (the one side) have a Primary (or unique) Key (PK), that uniquely identifies each row, and the "child" table (the other side) have a Foreign Key column or columns, that must be populated with values that are the same as some existing value[s] of the Primary Key in the parent table. If you want a one to many (1-M) relationship then the Foreign Key should be an ordinary attribute (column or columns) in the child table that can repeat (there can be many rows with the same value)
If you want a one to one (1-1) relationship then the Foreign key should itself be a Primary Key or unique index in the child table that guarantees that there may be at most one row in the child table with that value.
A 1-1 relationship effectively partitions the attributes (columns) in a table into two tables. This is called vertical segmentation. This is often done for sub-classing the table entities, or, for another reason, if the usage patterns on the columns in the table indicate that a few of the columns need to be accessed significantly more often than the rest of the columns. (Say one or two columns will be accessed 1000s of times per second and the other 40 columns will be accessed only once a month). Partitioning the table in this way in effect will optimize the storage pattern for those two different queries.
Sub-Classing. The above actually creates a 1 to zero or one relationship, which is used for what is called a sub-class or subtype relationship. This occurs when you have two different entities that share a great number of attributes, but one of the entities has additional attributes that the other does not need. A good example might be Employees, and SalariedEmployees. The Employee table would have all the attributes that all employees share, and the SalariedEmployee table would exist in a (1-0/1) relationship with Employees, with the additional attributes (Salary, AnnualVacation, etc.) that only Salaried employees need.
If you really want a 1-1 relationship, then you have to add another mechanism to guarantee that the child table will always have one record for each record/row in the parent table. Generally the only way to do this is by enforcing this in the code used to insert data (either in a trigger, stored procedure or code outside the database). This is because if you added referential integrity constraints on two tables that require that rows always be in both, it would not be possible to add a row to either one without violating one of the constraints, and you can't add a row to both tables at the same time.
One-to-One Relationship
Create Table ParentTable
(
PrimaryKeyCol ... not null Primary Key
, ...
)
Create Table ChildTable
(
, ForeignKeyCol ... [not] null [Primary Key, Unique]
, ...
, Constraint FK_ChildTable_ParentTable
Foreign Key ( ForeignKeyCol )
References ParentTable( PrimaryKeyCol )
)
In this case, I can never have more than one row in the ChildTable for a given ParentTable primary key value. Note that even in a One-to-One relationship, one of the tables is the "parent" table. What differentiates a One-to-One relationship from a One-to-Many relationship purely in terms of implementation is whether the ChildTable's foreign key value has a Unique or Primary Key constraint.
One-to-Many Relationship
Create Table ParentTable
(
PrimaryKeyCol ... not null Primary Key
, ...
)
Create Table ChildTable
(
, ForeignKeyCol ... [not] null
, ...
, Constraint FK_ChildTable_ParentTable
Foreign Key ( PrimaryKeyCol )
References ParentTable( PrimaryKeyCol )
)
In this scenario, I can have multiple rows in the ChildTable for a given ParentTable primary key value.
A 1:1 relationship exists where table A and table B only exist once in regards to each other.
Example: A student has 1 master student record. The student would be table A and the record in table B. Table B would contain a foreign key to the student record in table A (and possibly vice-versa)
A 1:m relationship exists where table A can be referenced or linked to by many entries in table B.
Example: A student can take several books out from the library. The student again would be table A and the book could be the entry in table B. The entry in table B would contain a foreign key to who checked the book out, and many books could reference the same student.

SQL: Copy records from child table to parent table, setting foreign key at the same time

I have 1-to-many relationship between two tables (Product and PLProduct respectively).
This is done through foreign key PLProduct.ParentProductId which relates to Product.Id.
The question is: how can I copy (orphan) records from PLProduct to Product table, setting foreign key at the same time?
These two simple SQL statements should do it. This assumes that your CHILD table has a proper PK, since we'll leverage that uniqueness to create a parent record.
--INSERT a parent record with a name containing the child ID
INSERT INTO Parent1
SELECT 'Child_' + CAST(ID as varchar) FROM Child1 WHERE ParentID IS NULL
--UPDATE the child table from a join to the parent table on the name field
UPDATE Child1
SET Child1.ParentID = Parent1.ID
FROM
Child1
JOIN Parent1 ON 'Child_' + CAST(Child1.ID as varchar) = Parent1.ParentName
I'm using SQL2000, devoid of any interesting tricks (would like to see what else turns up, though.)