Storing and retrieving multiple values from a foreign table - sql

I have one table "Books", with a column "genres" where I want to reference to another table that contains list of genres.
The problem is that want to store more then one genres in column.
E.g,
ID | Author | Title | Genres
2 | David Baldacci |Stone Cold | 1,4 (action thriller )
table "Books Genres" with 2 columns Id and Genre.
1 Action
2 Drama
3 Comedy
4 Thriller
5 Horror
Can something like this be done? or it's not practical and I should store genres as simple string?

The best way to solve this problem is with what is called a linking table.
A linking table would look like this:
ID (optional) | BookID| GenreID
1 2 1
2 2 4
Then each book could have multiple rows (or one) in this table.
(The optional ID would be useful if you care about row-level auditing of your tables, or transaction auditing -- you could use it to uniquely id this row -- for your problem it is not needed).

It can be done, but shouldn't.
It is bad database design - your database should be normalized.
I suggest an many-to-many table - with genreId and bookId columns (being foreign keys each, and together forming a composite primary key). This will work as the link you need (a book can have many genres, each genre can write many books).
Giving your book as an example with the Book Genres table, this would look like:
bookId genreId
2 1
2 4

You need a third table, perhaps called BookGenre which acts as a "resolver" for the many-many relationship. BookGenre would have two columns, BookID and GenreID. A row would be added to BookGenre for each book for each genre.
There would be two rows in BookGenre for the example data you provided:
BookID GenreID
2 1
2 4

Related

SQL insert command in relation table

Sorry I am newbie in SQL and I need help with a sql relation table.
I need to insert query to my relation table.
In my program, I have a book and this book has many categories.
Should I create a one to many, or many to many relations for that?
And how can I make insert command for adding a book to my table.
I tried to do somethings but i dont know its correct or not.
tblBook: BookID, BookName , CategoryID
tblCat : CatID, CatName,
I create foreign key
tblCat.CatID -> tblBook.CatID like as that. Do I need third table? Or is that enough?
Then I didn't understand how I will insert many category to book table?
Could you help me? thanks for advices.
You have to use a relation many to many, because one book can have different categories and one is for different book.
You need 3 tables:
tblBook: BookID, BookName
tblCat : CatID, CatName
tblRelationBookCat : BookID, CatID
To insert, you have to:
Add a book in your tblBook
INSERT INTO tblBook(BookID, BookName) VALUES(1, 'Star-Wars');
Add a category in your tblCat
INSERT INTO tblCat(CatID, CatName) VALUES(1, 'Sci-Fi');
Add the relation in your tblRelationBookCat
INSERT INTO tblRelationBookCat(BookID, CatID) VALUES(1,1);
Simply, you did a relation with two tables. You also should make one-to-many relation. That's OK and there is no need to create third table. In insertion, you need rows on category table. Because, when you adding a row with value of foreign key on book table logically you have to add a exists category id on category table's primary key.
Example :
tblCat | tblBook
-------------- | ---------
CatID CatName | BookID BookName CategoryID
1 Sci-Fi | 1 Star-Wars 1
2 Adventure | 2 Witcher 2
| 3 Romeo & Juliet 3 (???)
SQL Query :
INSERT INTO tblBook(BookName, CategoryID) VALUES('Star-Wars',1);

SQL: How to separate string values separated by commas?

I'm trying to create a relational database of all the movies I have watched.
I used IMDb to rate the movies I've seen and used the site's export capability to get the data in a .csv file which I uploaded to Microsoft Access. However, the "Genre" column is a many-to-many relationship that I am hoping to turn into a one-to-many relationship.
I would like to have a table called GENRE_ID that assigns each genre a numerical ID. Then I'd have another table where each instance would have the movie ID ("const"), line item number, and GENRE_ID.
So it might look like:
const line_item MOVIE_ID
tt0068646 1 1 (if MOVIE_ID: 1 = "crime")
tt0068646 2 2 (if MOVIE_ID: 2 = "drama")
Here's a link to the image of my database's current state. Thank you so much for your help. This is a project I'm doing to learn more on my own time.
Basically, when you have a one-to-many relationship, you should use a table for that relationship
In your case, I would recommend to have 3 table:
Film table : contains information like your current table ,except Genres
Genre table : contains (at least) Id and Name
Film_Genre table : contains Film_Id, GenreId.
For example
In your genre table, your data would be
row 1: Id =1 , Name = "Crime"
row 2: Id = 2, Name = drama,
and so on
your Film_Genre table would be something like:
row1: Film_Id = tt0068646, GenreId = 1,
row2: Film_Id = tt0068646, GenreId = 2
row3: Film_Id = tt0082971, GenreId = 2
and so on
(I supposed that you use "const" column as Id of Film table, if not, you should have your own Id)
Of course, it take you a litte bit effort to transform your current database to this database.
Some notes on a way to a solution.
A table of genres
ID Genre
1 Action
2 Adventure
3 Thriller
4 War
An import table
Const GenreList
tt00 Action, Adventure, Thriller, War
A query
SELECT ti.Const, ti.GenreList, tg.Genre
FROM Imports as ti, Genres as tg
WHERE ti.GenreList Like "*" & tg.Genre & "*"

Join Table vs Foreign Key/Ref

Imagine I have two tables and they have a 1-to-Many relationship. Is it better to have a Join table storing the relationship, or issuing a foreign key in one of these tables? Take a look of these two situations:
Situation A:
Table 1: CreditCard
Table 2: Person
It seems to me quite making sense to put the creditCard_id as part of the Person table
Situation B:
Table 1: Order
Table 2: Person
This time I think I will put the order_id and person_id in a Join table?
Am I making a mistake in the above? Is there a standard/better way of determining this?
For 1 to Many relation, people usually put the foreign key into the heavier table or the "Many" table.
So from your example, both go CreditCard and Order tables, by doing so you will remove duplicate data.
Imagine you which one is better:
FK goes to the "Many" table
Table People:
ID NAME
1 A
2 B
Table CreditCard:
ID PEOPLE_ID
1 1
2 1
FK goes to "1" table:
Table People:
ID NAME CreditCard_ID
1 A 1
1 A 2
2 B 3
Table CreditCard:
ID
1
2
3
Note: See how the ID and Name are repeated(ID=1, NAME=A) in the second example, that happens if you put the FK in the wrong table.
I would make three tables; a person table with all their info( name, address, etc. ), a credit card table with all the info( expiration date, security number?, etc.. ) then another table connecting them with the PersonID and CreditCardID. But what do I know, I'm still in school lol so wait for someone else to answer you.

How to change values of foreign keys in postgresql?

Let's say I have two tables: Customer and City. There are many Customers that live in the same City. The cities have an uid that is primary key. The customers have a foreign key reference to their respective city via Customer.city_uid.
I have to swap two City.uids with one another for external reasons. But the customers should stay attached to their cities. Therefore it is necessary to swap the Customer.city_uids as well. So I thought I first swap the City.uids and then change the Customer.city_uids accordingliy via an UPDATE-statement. Unfortunately, I can not do that since these uids are referenced from the Customer-table and PostgreSQL prevents me from doing that.
Is there an easy way of swapping the two City.uids with one another as well as the Customer.city_uids?
One solution could be:
BEGIN;
1. Drop foreign key
2. Make update
3. Create foreign key
COMMIT;
Or:
BEGIN;
1. Insert "new" correct information
2. Remove outdated information
COMMIT;
My instinct is to recommend not trying to change the city table's id field. But there is lot of information missing here. So it really is a feeling rather than a definitive point of view.
Instead, I would swap the values in the other fields of the city table. For example, change the name of city1 to city2's name, and vice-versa.
For example:
OLD TABLE NEW TABLE
id | name | population id | name | population
------------------------- -------------------------
1 | ABerg | 123456 1 | BBerg | 654321
2 | BBerg | 654321 2 | ABerg | 123456
3 | CBerg | 333333 3 | CBerg | 333333
(The ID was not touched, but the other values were swapped. Functionally the same as swapping the IDs, but with 'softer touch' queries that don't need to make any changes to table constraints, etc.)
Then, in your associated tables, you can do...
UPDATE
Customer
SET
city_uid = CASE WHEN city_uid = 1 THEN 2 ELSE 1 END
WHERE
city_uid IN (1,2)
But then, do you have other tables that reference city_uid? And if so, is it feasible for you to repeat that update on all those tables?
You could create two temporary cities.
You would have:
City 1
City 2
City Temp 1
City Temp 2
Then, you could do the follow:
Update all Customer UIDs from City 1 to City Temp 1.
Update all Customer UIDs from City 2 to City Temp 2.
Swap City 1 and 2 UIDs
Move all Customers back from City Temp 1 to City 1.
Move all Customers back from City Temp 2 to City 2.
Delete the temporally cities.
You can also add an ON UPDATE CASCADE clause to the parent table's CREATE TABLE statement, as described here:
How to do a cascading update?

SQL field with multiple id's of other table

Could someone give me an idea how to create this database structure.
Here is an example:
Table "countries":
id, countryname
1, "US"
2, "DE"
3, "FR"
4, "IT"
Now I have another table "products" and in there I would like to store all countries where this product is available:
Table "products":
id,productname,countries
1,"product1",(1,2,4) // available in countries US, DE, IT.
2,"product2",(2,3,4) // available in countries DE, FR, IT.
My question:
How do I design the table structure in "products" to be able to store multiple countries?
My best idea is to put a comma-separated string in there (i.e. "1,2,4"), then split that string to look up each entry. But I doubt that this the best way to do this?
EDIT: Thank you all for your help, amazing! It was difficult to choose the right answer,
I finally chose Gregs because he pointed me to a JOIN explanation and gave an example how to use it.
You need an intersection table for that many-to-many relationship.
Table Country
CountryID, CountryName
Table CountryProduct
CountryID, ProductID
Table Product
ProductID, ProductName
You then Inner Join all 3 tables to get your list of Countries & Products.
Select * From Country
Inner Join CountryProduct On Country.CountryID = CountryProduct.CountryID
Inner Join Product On CountryProduct.ProductID = Product.ProductID
Without denormalizing, you'll need to add an extra table
Table Product countries
ProductID CountryID
1 1
1 2
1 4...
What you're talking about is normalisation. You have a many-to-many structure, so you should create another table to link the two. You should never (ok, pretty much never) use delimited strings to store a list of values in a relational database.
Here's an example of the setup:
product_countries table
productid | countryid
----------+-----------
1 | 1
1 | 2
1 | 4
2 | 2
2 | 3
2 | 4
You can use a foreign key to each other table, then make them both into a composite primary key.
You can then get a list of supported products for a country ID like this:
SELECT * FROM products, product_countries
WHERE products.id = product_countries.productid
AND product_countries.countryid = $cid
You could also make a third table countries_products with fields country_id and product_id.
the best approach for relational databases is the following :
One table for coutries, let's say
country_id, country_desc (country_id is primary)
one table for products, let's say
product_id, product_desc and as many columns as you want (product_id is primary)
if you had only one country for sure, it'd be enough to have a foreign key pointing to country_id in each product row. Having a foreign key asserts that there is an actual country behing a country_id referring to country table.
In your case you have several countries for a product, so add a separate association table
product_id, country_id
both keys primary and both foreign as well.