SQL and relations between tables - sql

For serveral times I've been returning to understanding of database relational theory, and still I don't have success. I'll try once more.
Let's say I have two tables:
animals:
CREATE TABLE animals (id INTEGER PRIMARY KEY, name TEXT);
and food:
CREATE TABLE food (id INTEGER PRIMARY KEY, food TEXT);
What I need is to make this two tables connected. For example, I want to select 'pig' from animals table and recive all the things the pig can eat from food table.
I just don't get how to relate them. I belive I can add a foreign key to food table, which would link to the primary key of animal table, but there is an issue I can't figure out:
What if I make entries to the database from, for example, a web form, where I enter animal name and product which it eats. The animal name goes to the first table and automatically recieves an id. It just autoincrements. So, in order to make it a relation for the second table I must to select the new ID from the first table! So we got THREE sql requests:
1) INSERT INTO animals (name) VALUES ('pig);
2) SELECT id FROM animals WHERE name='pig'; (we store it in a variable, does not really matters for now)
3) INSERT INTO food (product, animal_id) VALUES ('something', 'id of a pig');
I just feel that it is wrong.
Or my mind is just not capable of understanding such complex abstractions.
Please advice.

You need a junction table, that related Animals and Food. This would look like:
CREATE TABLE AnimalFoods (
id INTEGER PRIMARY KEY,
AnimalId int references Animal(id),
FoodId int references Food(id)
);
You can then answer your questions using various joins among these tables.

That's how you implement such a many-to-many relationship:
How to implement a many-to-many relationship in PostgreSQL?
And you can accomplish the task you describe with a single query using a data-modifying CTE:
WITH ins AS (
INSERT INTO animals (name) VALUES ('pig')
RETURNING animal_id -- return generated ID immediately
)
INSERT INTO animal_food (food_id, animal_id) -- m:m link table
SELECT food_id, animal_id -- food_id passed as 2nd param
FROM ins;
Assuming we operate with a known-existing food (like it was select from a drop-down menu. Else you need one more step to look up the food or possibly INSERT a row there, too:
Is SELECT or INSERT in a function prone to race conditions?
... still a single query.
The linked answer provides some insight in the more tricky matter of race conditions with concurrent transactions.

Can an animal eat multiple foods? If not, then you can have animal be the primary key on food the food table. If animal can have multiple foods, then you can have an auto increment ID (just like the one in the animal table) in the food table. As jWeaver pointed out, have a parentID in the food table as the foreign key referencing the animal table.

Create an animal table with parentId and then in your food table use that parentId column to refer.
Example:
Animal(ParentId integer, NAME TEXT);
and
Food(FoodId integer, ParentId integer, Name Text);
That's it. Make sure, you are using same ParentId in food table to refer food for specific animal.
Hope, this make sense to you.

If different animals eat the same kind of food, you should define a table with foreign keys the id of the two related tables:
CREATE TABLE animals (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE food (id INTEGER PRIMARY KEY, food TEXT);
CREATE TABLE eat (animal_id INTEGER, food_id INTEGER,
FOREIGN KEY (animal_id) REFERENCES animals(id),
FOREIGN KEY (food_id) REFERENCES food(id));

Assuming an animal would eat multiple food and multiple animals could eat same food. You need to have a many-to-many association with animals and food.
Animal(id integer, name Text)
Food(id integer, name TEXT)
AnimalFood(animalId integer,foodId integer)
CREATE TABLE animals (id int(11) not null auto_increment primary key, name text);
CREATE TABLE foods (id int(11) not null auto_increment primary key, name text);
CREATE TABLE animal_foods (animal_id int(11) not null, food_id (11) not null);

Related

How to add references to multiple "tags"?

In my database, I have a table for "tags". So, in my main table, I want to give each item multiple tags.
For example, if my main table is dog, I want to add tags for small brown and mean. But in my tags table, I might have 50 possible tags. Each dog can have as many tags if I want.
How do I do that?
I don't really want to create one column for each tag in the main table with a boolean. Is there a way to specify multiple tags in one field?
(I'm rather not used to working with databases, so this probably sounds stupid.)
In the end, the goal is to be able to get all the dogs that match a particular tag.
You are describing a many-to-many relationship between dogs and tags. You would typically represent that with a bridge table, that references the two other referential tables, that store dogs and tags.
Assuming the following structures for the referential tables:
create table dogs (
dog_id int primary key,
name text
);
create table tags (
tag_id int primary key,
name text
);
You would create the bridge table as:
create table dogs_tags (
dog_id int references dogs(dog_id),
tag_id int references tags(tag_id),
primary key (dog_id, tag_id)
);

How can I simplify my SQL schema such that I have less tables but retain referential integrity?

Given the below SQL Server schema, how can I combine the CarWindow and HouseWindow tables into one table?
I would like to keep the foreign key constraint to Car if it is a car window, and to House if it is a house window.
I cannot combine the Car and House tables into one table because they are modelling different entities.
DROP TABLE IF EXISTS CarWindow
DROP TABLE IF EXISTS HouseWindow
DROP TABLE IF EXISTS Car
DROP TABLE IF EXISTS House
CREATE TABLE Car
(
Id int IDENTITY PRIMARY KEY,
CarColumn varchar(200)
)
CREATE TABLE House
(
Id int IDENTITY PRIMARY KEY,
HouseColumn_CompletelyDifferent int
)
CREATE TABLE CarWindow
(
IdCar int,
IsBroken bit,
CONSTRAINT fk_CarWindow_Car FOREIGN KEY (IdCar) REFERENCES Car(Id)
)
CREATE TABLE HouseWindow
(
IdHouse int,
IsBroken bit,
CONSTRAINT fk_HouseWindow_House FOREIGN KEY (IdHouse) REFERENCES House(Id)
)
A house presumably has multiple windows, some of which may be broken and some not. Same with a car. So I'm assuming, even though you haven't included it, that HouseWindow actually ought to have a primary key column called Id. Multiple HouseWindows will therefore have multiple Ids - but may share the same IdHouse.
And similarly for the cars and car windows case.
Implement a new table called ItemOfProperty. An item of property can be a car or a house.
CREATE TABLE ItemOfProperty
(
Id integer IDENTITY PRIMARY KEY,
ItemType char(1) NOT NULL,
ItemOfPropertyColumn varchar(200) ,
CONSTRAINT itemofproperty_id_itemtype_key UNIQUE (Id, ItemType),
CONSTRAINT itemofproperty_itemtype_check CHECK (ItemType in ('H', 'C'))
)
Car should have an ItemType attribute which is defaulted to 'C' (for Car), and should have a foreign key to ItemOfProperty:
CREATE TABLE Car
(
Id integer PRIMARY KEY,
ItemType char(1) NOT NULL DEFAULT 'C',
CarColumn varchar(200) ,
CONSTRAINT car_id_itemtype_fkey FOREIGN KEY (Id, ItemType) REFERENCES ItemOfProperty (Id, ItemType) ,
CONSTRAINT car_itemtype_check CHECK (ItemType = 'C')
)
Similarly for House:
CREATE TABLE House
(
Id integer PRIMARY KEY,
ItemType char(1) NOT NULL DEFAULT 'H',
HouseColumn_CompletelyDifferent integer,
CONSTRAINT house_id_itemtype_fkey FOREIGN KEY (Id, ItemType) REFERENCES ItemOfProperty (Id, ItemType),
CONSTRAINT house_itemtype_check CHECK (ItemType = 'H')
)
(Always insert an ItemOfProperty row prior to inserting its corresponding Car row or House row.)
Now, in the same way we've invented a thing called ItemOfProperty which can encompass cars and houses, we can also introduce a table called GenericWindow (which is what you've asked for) which encompasses car windows and house windows.
CarWindow and HouseWindow can reference GenericWindow in much the same way Car and House reference ItemOfProperty. And GenericWindow can reference ItemOfProperty. Because ItemType is used throughout, there is never any danger of a car window belonging to a generic window of the "house" type, nor of a house window belonging to a generic window of the "car" type.
Now you're free to add whatever non-car-specific / non-house-specific window attributes to GenericWindow, while keeping the car-window-specific attributes in CarWindow and the house-window-specific attributes in HouseWindow (EDIT - or ditch the CarWindow and HouseWindow tables entirely if you feel that generic window attributes are all you ever need).
Of course this type of approach could be extended beyond cars and houses, and beyond car windows and house windows. You'd need more tables, and more ItemTypes. But tables ItemOfProperty and GenericWindow would remain at the heart of the design.

SQL schema and ingredients list for cake recipe

I am new to PostgreSql and am working on an example database for learning purposes. I have a bakery database and a table for recipes and a table for ingredients. I am trying to understand the schema to connect the two tables such that the recipes table has a list of ingredients that references the ingredients table, but I am not sure if I need a 3rd table or if I can get away with just the two tables.
CREATE TABLE ingredients
(
ing_id SERIAL PRIMARY KEY,
name varchar(255) NOT NULL,
quantity integer NOT NULL
);
CREATE TABLE recipes
(
rec_id SERIAL PRIMARY KEY,
name varchar(120) NOT NULL,
list_of_ingredients text NOT NULL,
);
EDIT:
So let's say I have this in the ingredients table:
(1, flour, 40)
(2, eggs, 12)
(3, sugar, 23)
And this in the recipes table:
(1, cake, "3 flour, 4 eggs, 2 sugar")
I'm a bit confused on how to link the two tables.
The list_of_ingredients will need to reference the ingredients table as a foreign key. I understand that the whole point of NoSQL DBs is to allow for lists, so I'm not sure if I am approaching this totally wrong.
I will also write a Make_Recipe function that will take in a recipe and make sure there is enough ingredients, then will go ahead and decrease the ingredient quantity if it passes the above condition.
I have read through these posts, but they don't quite fit the bill:
Database design for storing food recipes
Database Schema for Recipe/Ingredient/Measurement/Amount
Thanks for your time! Any help is much appreciated.
The relationship between recipes and ingredients is what is known as a many-to-many relationship - a recipe might contain any number of ingredients, while an ingredient might be used by any number of recipes.
In a relational database (and PostgreSql is a relational database), the way to create a many-to-many relationship is by introducing a bridge table.
In the case of recipes and ingredients, you will have three tables.
One table for ingredients, specifying the name of the ingredient (and possibly other ingredient related data, if you can think of such data).
Another table for recipes, specifying the name of the recipe, a description, the text explanation ect', and the size of the dish.
Then you have the bridge table, ingredientToRecipe, that will contain a one-to-many foreign key to the recipe table, a one-to-many foreign key to the ingredient table, and the quantity needed for that specific ingredient in that specific recipe.
Remember the size of the dish in the recipe table? That would be needed to calculate up or down scaling of the quantity of ingredients when scaling up or down the size of the dish.
So, a DDL for these tables might look something like this:
CREATE TABLE ingredients
(
ing_id SERIAL PRIMARY KEY,
name varchar(255) NOT NULL
);
CREATE TABLE recipes
(
rec_id SERIAL PRIMARY KEY,
name varchar(120) NOT NULL,
description text NOT NULL,
DishSize integer NOT NULL
);
CREATE TABLE ingredientsToRecipes
(
rec_Id integer REFERENCES recipes (rec_id),
ing_id integer REFERENCES ingredients (ing_id),
quantity integer NOT NULL,
quantity_unit varchar(100) NOT NULL,
PRIMARY KEY(rec_Id, ing_id)
);

How to insert values into a junction/linking table in SQL Server?

I am piggy backing off this question regarding creating a junction/linking table. It is clear how to create a junction table, but I am concerned about how to fill the junction table with data. What is the simplest and/or best method for filling out the junction table (movie_writer_junction) with data between two other tables (movie, writer)
CREATE TABLE movie
(
movie_id INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
movie_name NVARCHAR(100),
title_date DATE
);
CREATE TABLE writer
(
writer_id INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
writer_name NVARCHAR(100),
birth_date DATE
);
INSERT INTO movie
VALUES ('Batman', '2015-12-12'), ('Robin', '2016-12-12'),
('Charzard, the movie', '2018-12-12')
INSERT INTO writer
VALUES ('Christopher', '1978-12-12'), ('Craig', '1989-12-12'),
('Ash', '1934-12-12')
CREATE TABLE movie_writer_junction
(
movie_id INT,
writer_id INT,
CONSTRAINT movie_writer_pk
PRIMARY KEY(movie_id, writer_id),
CONSTRAINT movie_id_fk
FOREIGN KEY(movie_id) REFERENCES movie(movie_id),
CONSTRAINT writer_fk
FOREIGN KEY(writer_id) REFERENCES writer(writer_id)
);
The final junction table is currently empty. This is a simple example, and you can manually fill the data into the junction table, but if I have two tables with millions of rows, how is something like this completed?
Hi I'm guessing this relates to the fact that you can't rely on the Identity Columns being the same in different regions.
You can write your inserts as a cross join from the 2 src tables
Insert junc_table (writer_id, movie_id)
Select writer_id , movie_id
from writer
CROSS Join
movie
where writer_name = 'Tolkien' and movie_name = 'Lord of the Ring'
This way you always get the correct Surrogate Key (the identity) from both tables.
Its pretty easy to generate a SQL statement for all your existing junction combinations using a bit of Dynamic SQL
Another Approach is to Use SET IDENTITY_INSERT ON - but this needs to be done when loading the 2 other tables and that ship may already have sailed!

How do I realize this 3 simple things in SQL?

i am an absolute SQL beginner and i already did search a lot with google but didnt find what i needed. So how do i realize in SQL(translated from a ER-Model):
An Entity having an Atribute that can have mulitple Entrys(I already found the ARRAY contstraint but i am unsure about that)
An Entity having an Atribute that consists itself of a few more Atributes(Picture: http://static3.creately.com/blog/wp-content/uploads/2012/03/Attributes-ER-Diagrams.jpeg)
Something like a isA Relation. And especially the total/partial and the disjunct characteristics.
Thanks already
In Postgres you have all three of this:
create table one
(
id integer primary key,
tags text[] -- can store multiple tags in a single column
);
A single column with multiple attributes can be done through a record type:
create type address as (number integer, street varchar(100), city varchar(100));
create table customer
(
id integer primary key,
name varchar(100) not null,
billing_address address
);
An isA relation can be done using inheritance
create table paying_customer
(
paid_at timestamp not null,
paid_amount decimal(14,2) not null
)
inherits (customer);
A paying customer has all attributes of a customer plus the time when the invoice was paid.