Many-to-one with table records requiring one another - sql

I have two tables: Talks and Days. Talks looks something like:
+----+----------------------------------+--------+
| Id | Name | Leader |
+----+----------------------------------+--------+
| 1 | How to improve revenue for tacos | Tacob |
| 2 | Improving sales potential | Bocat |
+----+----------------------------------+--------+
and the Days:
+--------+-----+
| TalkId | Day |
+--------+-----+
| 1 | Mon |
| 1 | Tue |
| 1 | Thu |
| 2 | Mon |
| 2 | Tue |
+--------+-----+
TalkId is a foreign key referencing the Talks table.
The foreign key enforces the relationship of "A Day requires a Talk". However, I would like to also enforce the reverse relationship "A Talk requires at least a Day".
I know that this constraint is similar to a Many-to-many relationship, where both records depend on each other. However, in this case, many days reference a talk but only one talk references many days.
Another problem is that after creating such a constraint, how would one insert both records at once?
I have searched for other questions and only found cases of Many-to-many relationships which will turn out like so:
+----+----------------------------------+--------+
| Id | Name | Leader |
+----+----------------------------------+--------+
| 1 | How to improve revenue for tacos | Tacob |
| 2 | Improving sales potential | Bocat |
+----+----------------------------------+--------+
+----+-----+
| Id | Day |
+----+-----+
| 1 | Mon |
| 2 | Tue |
| 3 | Thu |
| 4 | Mon |
| 5 | Tue |
+----+-----+
+--------+-------+
| TalkId | DayId |
+--------+-------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 4 |
| 2 | 5 |
+--------+-------+
Where TalkId references Talks's Id and DayId references Days's Id.
Edit:
Ignore what I requested for above.
What I hope to be able to do:
SELECT all valid Talks
SELECT all valid Days
What I hope to be unable to do:
INSERT a Talk without a Day
INSERT a Day without a Talk

It sounds like you want a simple foreign key relationship:
alter table days add constraint fk_days_talkid foreign key (talkid) references talks(talkid);
This guarantees that talkid is valid. Then you declare days.talkid to be not null and you are guaranteeing the relationship you describe.

-- Day named (TheDay) exists.
--
Calendar {TheDay}
PK {TheDay}
-- Talk (TalkID) titled (TalkName), presented by (Leader) is by default
-- scheduled on (DefaultDay).
Talk {TalkID, TalkName, Leader, DefaultDay}
PK {TalkID}
AK {TalkName}
FOREIGN KEY {DefaultDay} REFERENCES Calendar {TheDay}
--Talk (TalkID) is also scheduled on (TheDay).
--
TalkDay {TalkID, TheDay}
PK {TalkID, TheDay}
FOREIGN KEY {TalkID} REFERENCES Talk {TalkID}
FOREIGN KEY {TheDay} REFERENCES Calendar {TheDay}
Note PK = primary key
AK = alternate key (unique)
All attributes (columns) NOT NULL
Select all days for a specific talk:
select TalkName, DefaultDay as TalkDay
from Talk
where TalkName = 'How to improve revenue for tacos'
union
select TalkName, b.TheDay as TalkDay
from Talk as a
join TalkDay as b on b.TalkID = a.TalkID
where a.TalkName = 'How to improve revenue for tacos'
Select all talks on a specific day:
select TalkName, DefaultDay as TalkDay
from Talk
where DefaultDay = 'Tue'
union
select TalkName, b.TheDay as TalkDay
from Talk as a
join TalkDay as b on b.TalkID = a.TalkID
where b.TheDay = 'Tue'

Related

Check logical constraints through SQL nested references

Let a SQL schema with 4 tables and nested references
For example modeling a restaurant, with a different menu every weekday, and some customer who have booked a table for one day and want to order a meal :
+------+
| days |
+----------+
| day |
+----------+
| friday |
| saturday |
| sunday |
+----------+
┐ ┌
+-------+ / \
| meals | +-----------+
+------------+----------+ | customers |
| meal | day (*) | +----------+---------+
+------------+----------+ | customer | day (*) |
| pizza | friday | +----------+---------+
| tacos | friday | | Joe | friday |
| chicken | saturday | | Alice | sunday |
| fish&chips | sunday | | Oscar | sunday |
| paella | sunday | +----------+---------+
+------------+----------+
┌ ┐
\ /
+--------+
| orders |
+--------------+----------+
| customer (*) | meal (*) |
+--------------+----------+
| Joe | pizza |
| Oscar | paella |
+--------------+----------+
(Foreign keys are marked with (*), and I tried to express references with arrows)
I want to prevent Alice from ordering some chicken, since she is planned on sunday, and chicken is planned on saturday.
In other words, for each record in orders,
orders.meal refers to a record of meals, and meals.day refers to a record of days
orders.customer refers to a record of customers, and customers.day refers to a record of days
and the days referred to must be the same.
Is there any SQL-way to check this constraint at INSERT / UPDATE ?
What you can do is declare "super keys" in your meals and customers tables, a key declared across both the meal/customer column and the day column.
That makes those pairs of columns valid references for a foreign key constraint. In turn, that then means that you can add the day column to the orders table and include day in your foreign key references.
If needs be, one can then declare a view over the orders table to conceal the day column, and make that view, rather than the orders table, be the way that applications interact with the database, closely mimicking your existing structure. The only complexity is in populating the day column during insert and update. One way to deal with that is via triggers on the view.

RDBMS: Generating a locally Unique Key for a Relational Table with Foreign Key

Below is the schema of the database.
There are multiple screenplays each identified by a globally unique key.
Multiple scenes can exist for a screenplay and linked by foreign key.
The obvious choice for me for scene_id of Scene table was to use an auto-increment Integer field type which will ensure each scene in Scene table has a globally unique key across all the multiple screenplays.
Now, the query is:
What is the best way for generating scene_id for Scene table?
Isn't keeping a globally unique key an overkill when the
scene_id needs to be unique only within a particular Screenplay?
A sample table
+----------+------------+-----------------+------+
| Scene_Id | Scene_Name | Scrn_ID | |
+----------+------------+-----------------+------+
| 1 | | Opening Scene | 1001 |
| 2 | | Climax Scene | 1001 |
| 3 | | End Credits | 1001 |
| 1 | | Opening Scene 1 | 1002 |
| 2 | | Character Intro | 1002 |
| 3 | | Conflict | 1002 |
| 4 | | Climax Scene | 1002 |
+----------+------------+-----------------+------+
Using an automatically generated primary key is actually the simplest solution:
scene_id bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY
There is very little overhead in this.
It would be much more complicated and expensive to use numbers that are relative to scm_id – see the many questions for such a feature on this forum.
Keep it simple!

Calculate Equation From Seperate Tables Data

I'm working on my senior High School Project and am reaching out to the community for help! (As my teacher doesn't know the answer to my question).
I have a simple "Products" table as shown below:
I also have a "Orders" table shown below:
Is there a way I can create a field in the "Orders" table named "Total Cost", and make that automaticly calculate the total cost from all the products selected?
Firstly, I would advise against storing calculated values, and would also strongly advise against using calculated fields in tables. In general, calculations should be performed by queries.
I would also strongly advise against the use of multivalued fields, as your images appear to show.
In general, when following the rules of database normalisation, most sales databases are structured in a very similar manner, containing with the following main tables (amongst others):
Products (aka Stock Items)
Customers
Order Header
Order Line (aka Order Detail)
A good example for you to learn from would be the classic Northwind sample database provided free of charge as a template for MS Access.
With the above structure, observe that each table serves a purpose with each record storing information pertaining to a single entity (whether it be a single product, single customer, single order, or single order line).
For example, you might have something like:
Products
Primary Key: Prd_ID
+--------+-----------+-----------+
| Prd_ID | Prd_Desc | Prd_Price |
+--------+-----------+-----------+
| 1 | Americano | $8.00 |
| 2 | Mocha | $6.00 |
| 3 | Latte | $5.00 |
+--------+-----------+-----------+
Customers
Primary Key: Cus_ID
+--------+--------------+
| Cus_ID | Cus_Name |
+--------+--------------+
| 1 | Joe Bloggs |
| 2 | Robert Smith |
| 3 | Lee Mac |
+--------+--------------+
Order Header
Primary Key: Ord_ID
Foreign Keys: Ord_Cust
+--------+----------+------------+
| Ord_ID | Ord_Cust | Ord_Date |
+--------+----------+------------+
| 1 | 1 | 2020-02-16 |
| 2 | 1 | 2020-01-15 |
| 3 | 2 | 2020-02-15 |
+--------+----------+------------+
Order Line
Primary Key: Orl_Order + Orl_Line
Foreign Keys: Orl_Order, Orl_Prod
+-----------+----------+----------+---------+
| Orl_Order | Orl_Line | Orl_Prod | Orl_Qty |
+-----------+----------+----------+---------+
| 1 | 1 | 1 | 2 |
| 1 | 2 | 3 | 1 |
| 2 | 1 | 2 | 1 |
| 3 | 1 | 1 | 4 |
| 3 | 2 | 3 | 2 |
+-----------+----------+----------+---------+
You might also opt to store the product description & price on the order line records, so that these are retained at the point of sale, as the information in the Products table is likely to change over time.

Which normal form or other formal rule does this database design choice violate?

The project I'm working on is an application that lets you design data entry forms, and automagically generates a schema in an underlying PostgreSQL database
to persist them as well as the browsing and editing UI.
The use case I've encountered this with is a store back-office database, but the app itself intends to be somewhat universal. The administrator creates the following entry forms with the given fields:
Customers
name (text box)
Items
name (text box)
stock (number field)
Order
customer (combo box selecting a customer)
order lines (a grid showing order lines)
OrderLine
item (combo box selecting an item)
count (number field)
When all this is done, the resulting database schema will be equivalent to this:
create table Customers(id serial primary key,
name varchar);
create table Items(id serial primary key,
name varchar,
stock integer);
create table Orders(id serial primary key);
create table OrderLines(id serial primary key,
count integer);
create table Links(id serial primary key,
fk1 integer references Customers.id,
fk2 integer references Items.id,
fk3 integer references Orders.id,
fk4 integer references OrderLines.id);
Links being a special table that stores all the relationships between entities; every row has (usually) two of the foreign keys set to a value, and the rest set to NULL. Whenever a new entry form is added to the application instance, a new foreign key referencing the table for this form is added to Links.
So, suppose our shop stocks some widgets, gizmos, and thingeys. A customer named Adam orders two widgets and three gizmos, and Betty orders four gizmos and five thingeys. The database will contain the following data:
Customers
/----+-------\
| ID | NAME |
| 1 | Adam |
| 2 | Betty |
\----+-------/
Items
/----+---------+-------\
| ID | NAME | STOCK |
| 1 | widget | 123 |
| 2 | gizmo | 456 |
| 3 | thingey | 789 |
\----+---------+-------/
Orders
/----\
| ID |
| 1 |
| 2 |
\----/
OrderLines
/----+-------\
| ID | COUNT |
| 1 | 2 |
| 2 | 3 |
| 3 | 4 |
| 4 | 5 |
\----+-------/
Links
/----+------+------+------+------\
| ID | FK1 | FK2 | FK3 | FK4 |
| 1 | 1 | NULL | 1 | NULL |
| 2 | 2 | NULL | 2 | NULL |
| 3 | NULL | NULL | 1 | 1 |
| 4 | NULL | NULL | 1 | 2 |
| 5 | NULL | NULL | 2 | 3 |
| 6 | NULL | NULL | 2 | 4 |
| 7 | NULL | 1 | NULL | 1 |
| 8 | NULL | 2 | NULL | 2 |
| 9 | NULL | 2 | NULL | 3 |
| 10 | NULL | 3 | NULL | 4 |
\----+------+------+------+------/
(The tables also contain a bunch of timestamps for auditing and soft deletion but I don't think they're relevant here, they just make writing the SQL by the administrator that much messier. The management app is also used to implement a bunch of different use cases, but they're generally primarily data entry, master-detail views, and either scalar fields or selection boxes.)
When I've had to write a join through this thing I'd grumbled about it to my coworker, who replied "well using separate tables for each relationship is one way to do it, this is another..." Leaving aside the obvious-to-me ugliness of the above and the practical issues, I also have a nagging feeling this has to be a violation of some normal form, but it's been a while since college and I'm struggling to figure out which of the criteria apply here.
Is there something stronger "well that's just your opinion" I can use when critiquing this design?

SQL Server Delete - Foreign Key

I have got two tables in SQL Server 2005:
USER Table: information about user and so on.
COUNTRY Table : Holds list of whole countries on the world.
USER_COUNTRY Table: Which matches, which user has visited which county.
It holds, UserID and CountryID.
For example, USER_COUNTRY table looks like this:
+----+--------+-----------+
| ID | UserID | CountryID |
+----+--------+-----------+
| 1 | 1 | 34 |
| 2 | 1 | 5 |
| 3 | 2 | 17 |
| 4 | 2 | 12 |
| 5 | 2 | 21 |
| 6 | 3 | 19 |
+----+--------+-----------+
My question is that: When a user is deleted in USER table, how can I make associated records in USER_COUNTRY table deleted directly. Maybe, by using Foreign Key Constaint?
You have to define a foreign key in USER_COUNTRY that points to USER.UserID and set cascaded deletion:
CREATE TABLE USER_COUNTRY (
...
CONSTRAINT USER_COUNTRY_FK1 FOREIGN KEY (UserID)
REFERENCES USER(UserID)
ON DELETE CASCADE
);
Yes, you could set your foreign key relationship Delete rule to Cascade.
I guess CASCADE is your only option. But do you really want to hard delete records like this? Context: I'm a data fiend.