Reading an SQL record and all descendants - sql

What would be the most efficient way to selectively read records from a SQL table, along with all their descendants - i.e., records in other tables with different schemas but of the same database, referencing the starting table via foreign keys?
For example, the following 4 tables have a primary key called id and records in Table A are referenced from the other 3 tables via the column x_id, where x = B, C, or D and x_id is the foreign key pointing to a record of Table X with primary key id.
Table A: id
Table B: id, a_id
Table C: id, a_id, b_id
Table D: id, a_id, c_id
Assuming that somehow the application knows the "graph" of table foreign key dependencies and thus can enumerate all "children" of a record (i.e., all records from other tables directly referencing it via its id), the data can be retrieved via multiple SELECT queries. That, however, becomes very slow for large tables.
Is there any more efficient way of getting the same information?

Related

Use a single join table to join between one main table and multiple secondary tables (but only to one in each case)

I'm currently designing a system where we use Postgres as the backend. In that system users can upload files, and those files can be attached to various objects, where each object has it's own table. Currently I'm using a separate join table for each object to the file table, i.e. the DB layout looks something like this:
table File
table A
table A_to_File
table B
table B_to_File
table C
table C_to_File
Each join table has two columns, one for the id of the file, one for the id of the object in the object table, and both columns are defined as foreign keys on the respective tables.
Now this results in quiet a few database tables, and I was wondering if there is an elegant solution to replace those join tables with just a single one, where the column with the foreign key is dynamic and points to either the tables A, B or C (with some hint to which object table is used in that row). So in my imagination a table that would be created this way:
CREATE TABLE object_to_file (
object_id int NOT NULL,
file_id int NOT NULL,
FOREIGN KEY (file_id) REFERENCES File(id),
FOREIGN KEY (object_id) REFERENCES (A(id) of B(id) or C(id))
)
Is this in any way possible, or in another manner? I'm basically just curious, given that the current solution works just fine.

Created a join table with a Primary Key column, and two Foreign Key columns, not pulling in data

I created a new table called Expirations that has it's own unique id, with indentity incrementing, as it's primary key. I also want this table to pull in data from two other tables, so I created a column for the InsuranceId and the LicenseId, making both columns foreign keys to connect them to the data (aka ID) from their respective tables (Insurance and License).
Any idea why my data is not automatically filling in for my Expirations Table? I believe it was created as "many to one" for all of these columns. Not sure if that is correct either, as I want the Expiration table to list all insurance id's and licence id's.
Anyone know what I am doing wrong here?
Foreign keys don't mean that a table gets filled automatically.
Let's say you have a person table and a company table and a company_person table to show which person works in which company. Now you insert three companies and four persons. That doesn't mean that the company_person table gets filled with 3 x 4 = 12 records (i.e. all persons work in all companies). That would make no sense.
Foreign keys merely guarantee that you cannot insert invalid data (i.e. a person that doesn't exist or a company that doesn't exist) into the table in question. You must insert the records yourself.
Basically your expirations table is like a fact table and you want to load data from the dim table which is Insurancetable ( InsuranceId as primarykey) and Licencetable ( Licenceid as PK).
But if you do not have any combination of InsuranceId and licenseId how do you know which insuranceid belongs to which LicenseId.
If your expirations table is empty then you need to first do cross join between the insurancetable and licensetable which is cartesian result but you do not want to do that as it does not make sense in real world.
Hope my explanation helps.

SQL Join Table for Single Table to Self

I'm trying to create a table in Postgres to represent a many-to-many relationship between rows of the same table.
I have a table called outerwear (which is like jackets, etc) and I want to create a many-to-many relationship between instances of outerwear.
I'm wondering what the best way is to create a join table to model this relationship that takes into account the fact that A to B is the same as B to A. So far I have this (which is just a normal join table):
CREATE TABLE outerwear_outerwear_join (
a_outerwear_id integer REFERENCES outerwear,
b_outerwear_id integer REFERENCES outerwear,
PRIMARY KEY(a_outerwear_id, b_outerwear_id)
);
But again this does not account for the fact that flipping the order of the columns should not change the value/uniqueness of a row.
Create a UNIQUE INDEX , using least and greatest functions.
CREATE UNIQUE INDEX unq_test_a_b
ON outerwear_outerwear_join ( LEAST(a_outerwear_id, b_outerwear_id), GREATEST(
a_outerwear_id, b_outerwear_id));
Demo

Both sides of a many to many relationship also relate to the same 3rd party

In a relational database. Two tables can be related in a many to many fashion with a mapping table that has foreign keys to the other two tables primary keys, while both still being related to another table.
For example.
Table A
AId -PK
CId -FK
Table B
BId -PK
CId -FK
Mapping Table m
AId -FK
BId -FK
(composite PK of the above)
Table C
CId -PK
How would I modify this so both the tables in the many to many relationship setup in such a way that a row from Table A and a row from Table B can only be related to each other through mapping table m if the row in A and B are also related to the same row in Table C?
1. Make TableA.CId and TableB.CId both FKs to Table C.ID.
2. Add a unique index in TableA on columns AId and CId.
3. Add a unique index in TableB on columns BId and CId.
4. Add a CId column to TableM.
5. Then Add two FKs in Table M,
a. One using columns (AId, CId) pointing to Unique composite Index in Table A, and
b. the other using columns (BId, CId) pointing to Unique composite Index in Table B.

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.