Creating a database. Design help needed - sql

I am practicing python flask and I am going to make a very simple music site and am now creating the database.
I am new to databases so I just wanted help to see if the tables and relations are correct.
Also would I store multiple song ID's in the playlist_songs songID column?
userTable
userID (PK), username, email, password, level
songTable
songID (PK), songName, songArtist, songGenre, songDuration
playlistTable
playlistID (PK), userID (FK), playlistName, playlistDescription
playlist_songs
playlistID (FK), songID (FK)

As requested, I'm adding some collective info based on your question and comments.
Your design looks fine. As recommended by Rowland, it could perhaps use an order column. Something to order by. If you choose not to add this the songs will be returned in a somewhat random order for the playlist, or you could order by the SongId column and be guaranteed the same order at least (within a playlist). But it wouldn't be changeable.
You asked how data was entered in to the playlist_songs table:
SongTable
SongId | SongName | ...
-----------------------------
1 | Happy Bithday | ...
2 | Last Christmas | ...
3 | Christmas tree | ...
4 | Some song | ...
PlaylistTable
PlaylistId | PlaylistName | ...
-------------------------------------
1 | My Birthday songs | ...
2 | My Christmas songs | ...
3 | All my songs | ...
Playlist_songs
PlaylistId (FK) | SongId (FK)
-----------------------------
1 | 1
2 | 2
2 | 3
3 | 1
3 | 2
3 | 3
3 | 4
As you can see the Playlist_songs table can contain many playlists and many songs. If you query Playlist_songs for PlaylistId = 2 it will return SongId 2 & 3, and so on.
Currently, a primary key would have to be a constraint on the two columns (a compound key). This is also where you could add an Order column, or just add a stand alone primary key (Id for example) and order by that.

Related

Best practice to fill a table that relates to another with a foreign key

I would like to ask what would be the best approach (performance-wise) to split a table into two and relate them with a foreign key.
Lets assume that there is a table that contains tracks called
rawdata:
title | artist | album
----------------------------+-----------+---------------
Another One Bites The Dust | Queen | Greatest Hits
Asche Zu Asche | Rammstein | Herzeleid
Beauty School Dropout | Various | Grease
and a table albums that contain the distinct album titles bound to an id.
id | title
----+---------------
2 | Greatest Hits
29 | Grease
30 | Herzeleid
I would like to fill table tracks where the album_id would be a foreign key to albums, but I want to figure out which is the optimal way to do so.
id | title | album_id
----+----------------------------+----------
1 | Another One Bites The Dust | 2
2 | Asche Zu Asche | 30
3 | Beauty School Dropout | 29
I have came up with two ideas:
a. Use a join:
INSERT INTO tracks(title, album_id)
SELECT rawdata.title, album.id
FROM rawdata
LEFT JOIN album ON album.title = rawdata.album;
b. Use a SELECT - FROM two tables
INSERT INTO tracks(title, album_id)
SELECT rawdata.title, album.id
FROM rawdata, album
WHERE album.title = rawdata.album;
Is any of them better than the other?
Is there any better way to do so?

How would you store in database who's liked something?

How should database store whos liked a certain post, should I have a seperate table which keeps tracks of all likes, and keeps every like of every post together, storing article_id, user_id, and like/dislike?
Thanks!
You are describing a N-M relationship between users and posts, where each user might ligke serveral posts and each post can be liked by several users.
I would recommend using a bridge table, with foreign keys refering the posts and users tables.
In a nutshell, that would look like:
table: users
user_id
name
...
table: posts
post_id
title
...
table: users_like_posts
user_id -- foreign key to users(user_id)
post_id -- foreign key to posts(post_id)
like_dislike
One option could be creating a table which trucks likes and dislikes:
Example:
Like and dislike could be boolean or anything else that you like to implement.
Table:Like
-----------------
id | post_id | user_id | like_dislike |
1 | 1234 | 13783 | 0 |
2 | 1234 | 12083 | 1 |

Migrating legacy table to normalized data structure with foreign keys in Oracle SQL

I am having some trouble wrapping my head around remaking databases. I have a book database that includes only one table, where all of the authors data is included after each book. I'm trying to remake this database in order to have an author table and a book table.
I made the author table using :
CREATE TABLE AUTHORS
AS SELECT AUTHOR_NAME, AUTHOR_SURNAME, AUTHOR_BIRTHDATE
If I now want to remake the book table, how do I add the foreign key so that the author of each book will be the correct one? That is, if the first entry on the original book table was:
ISBN1 Title1 Author_Name1 Author_Surname1 Author_Birthdate1
How do I import this data into the new table so that the new author field, a foreign key, references the correct entry in the author table? Sorry if it's confusing.
You are looking to split the existing table into two tables, one to store the authors and the other for books. For this to work properly, you need to create a unique id for each author. Here is a step by step approach.
Assuming the following legacy data structure:
create table old_books (
isbn NUMBER(13, 0),
title VARCHAR2(200),
author_name VARCHAR2(200),
author_surname VARCHAR2(200),
author_birthdate DATE
);
And this sample data:
ISBN | TITLE | AUTHOR_NAME | AUTHOR_SURNAME | AUTHOR_BIRTHDATE
------------: | :----- | :---------- | :------------- | :---------------
1000000000001 | book 1 | name 1 | surname 1 | 01-MAR-90
1000000000002 | book 2 | name 2 | surname 2 | 01-MAR-95
1000000000003 | book 3 | name 1 | surname 1 | 01-MAR-90
First, let's create and feed the new data structure for authors (note that you don't want to use CREATE TABLE AS SELECT ... because this does not let you add constraints or other useful options).
To generate a unique author id, we use the IDENTITY feature (available starting Oracle 12c - without this feature, we would need to create a sequence and a trigger).
In legacy data, we assume that each author is uniquely identified by its name, surname and birthdate:
CREATE TABLE authors (
id NUMBER GENERATED ALWAYS AS IDENTITY,
name VARCHAR2(200),
surname VARCHAR2(200),
birthdate DATE,
PRIMARY KEY (id)
);
INSERT INTO AUTHORS (name, surname, birthdate)
SELECT DISTINCT author_name, author_surname, author_birthdate FROM old_books;
2 rows affected
SELECT * FROM authors;
ID | NAME | SURNAME | BIRTHDATE
-: | :----- | :-------- | :--------
1 | name 1 | surname 1 | 01-MAR-90
2 | name 2 | surname 2 | 01-MAR-95
With this first table in place, we can now create the books table. It contains a foreign key that references the primary key of the authors table. To feed the table, we need to join the legacy table with the new authors table to recover the id of each author:
CREATE TABLE books (
isbn NUMBER(13, 0),
title VARCHAR2(200),
author_id NUMBER,
CONSTRAINT book_author FOREIGN KEY(author_id) REFERENCES authors(id),
PRIMARY KEY (isbn)
);
INSERT INTO books(isbn, title, author_id)
SELECT ob.isbn, ob.title, a.id
FROM old_books ob
INNER JOIN authors a
ON a.name = ob.author_name
AND a.surname = ob.author_surname
AND a.birthdate = ob.author_birthdate;
3 rows affected
SELECT * FROM books;
ISBN | TITLE | AUTHOR_ID
------------: | :----- | --------:
1000000000001 | book 1 | 1
1000000000002 | book 2 | 2
1000000000003 | book 3 | 1
All set! Data is properly spread between the two tables, with the proper constraints in place. We can join both tables with a query like:
SELECT b.isbn, b.title, a.name, a.surname, a.birthdate
FROM authors a
INNER JOIN books b ON a.id = b.author_id;
ISBN | TITLE | NAME | SURNAME | BIRTHDATE
------------: | :----- | :----- | :-------- | :--------
1000000000001 | book 1 | name 1 | surname 1 | 01-MAR-90
1000000000002 | book 2 | name 2 | surname 2 | 01-MAR-95
1000000000003 | book 3 | name 1 | surname 1 | 01-MAR-90
You say that an author's first name plus surname are your author table's primary key. This is a valid approach. In case of two authors with the same name you'd have to find a solution like 'John' + 'Smith' and 'John R.' + 'Smith' or 'John' + 'Smith (the fantasy author)'. This is called a natural composite key, albeit not a perfect one as we may have to deal with duplicate names as mentioned. On the other hand there exist authors with the same name, so we may face this problem right away ;-)
Books are identified by their ISBN, which makes for an even better natural key, because there can be no duplicates. (Only if you wanted to add very old books or self-marketed books that have no ISBN, you'd have to create a fake ISBN.)
In order to have your book referring to an author, you must include the whole key, which is first and surname here. This is no redundancy, as this is the key needed to identify an author in your database.
CREATE TABLE books AS SELECT isbn, title, author_name, author_surname FROM old_table;
ALTER TABLE books ADD CONSTRAINT fk_book_author FOREIGN KEY (author_name, author_surname)
REFERENCES authors (author_name, author_surname);
An alternative would be to introduce surrogate (i.e. technical) keys. You would generate an ID (a number) for each book and each author and work with them. (That means the book table would contain an author_id.) But for a good database you should still think about what identifies a row naturally. This makes it easier for people who write the queries later. (E.g. someone asks to select a list of authors and the number of books they've written. How to write that query? Does it suffice to show first and surname or could we end up with two rows "John Smith | 5" and "John Smith | 2" and the enquirer saying they cannot use this ambiguous result?) Even when providing surrogate keys you should still have a unique constraint on the natural key, if there is one. For books with optional ISBNs this may be title + author_id and for authors it could be first name + surname + date of birth.
By the way: There exist books with more than one author ;-)

Inserting data into many-to-many relationship table

I'm trying to build a database with multiple tables for a study/research. This is the first time I'm designing database of this magnitude; the database grows by 100-200 records a day, and so far I have the data since 2010. Out of all the data, Generic Sequence Number, Product Name and the Strength of a drug (prescription) is slightly bothering me. This is what I have done so far:
Generic Seq number is unique to the strength of drug (product name). So, I have a table that contains id, generic seq no, and strength. Another table is for prod_id and product name. Each Generic seq number may have one or more product name, and each product name may have different generic seq number based on the strength. So, I set it up as many-to-many relationship. I created another table for this relationship that contains rx_id, drug_id, and prod_id. Since many patients may be prescribed for the same drug, the drug_id and prod_id may repeat several times in the rx_table.
My first question is, is this design appropriate?
How should I insert the data into rx_table? Should I create new record every time for new data even if the drug_id and prod_id already exist in the rx_table, or should I look for the rx_id where the drug_id and prod_id sequence exist and insert the rx_id into the other main table (not shown) which contains other data.
Or is this question too vague?
Thank you for your help.
I don't know what exactly is your Generic Sequence Number so i'll just use a real life drug example. From your description i think it's pretty similar to your application. Lets say you have Paracetamol as an agent. Then your Generic Sequence Number table would be something like
drug_id | generic_seq_no | strength
--------+--------------------+----------
1 | Paracetamol-100 | 100
2 | Paracetamol-250 | 250
3 | Paracetamol-500 | 500
Your product table would contain the names of the trademarks:
prod_id | prod_name
----------+------------
1 | Tylenol
2 | Captin
3 | Panadol
the rx_table contains the combinations of trademark name, agent and strength:
rx_id | drug_id | prod_id
-------+----------+----------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 1
5 | 2 | 2
6 | 3 | 2
7 | 3 | 3
So e.g. the first row would be Tylenol, containing 100 mg of Paracetamol. Now you have what can be prescribed by a doctor and that's what you already did so far. So as i said your approach is fine.
Now you need (or have?) another table with all your patients
patient_id | firstname | lastname
-----------+-----------+-----------
1 | John | Doe
2 | Jane | Doe
In the end, you must link your trademark/agent/strength combination to the patients. Since one patient may get different drugs and multiple patients may get the same drug you need another many-to-many-relation, let's call it prescription
prescription_id | patient_id | rx_id
----------------+------------+------
1 | 1 | 1
2 | 1 | 3
3 | 2 | 4
This means John Doe will get Tylenol and Panadol containing 100 mg Paracetamol each. Jane Doe will receive Tylenol with 250 mg Paracetamol. I think the table you will be inserting the most is the prescription table in this model.

Insert two tables value to already exist tables

I have two tables album_new and song_new. song_new table had column album_id, by this relation i can know which album has how many song. where album_id and song_id are auto-increment.
album_new
album_id | album_name
---------+-----------
1 | abs
2 | def
song_new
song_id | album_id | song_name
1 | 1 | yahoo
2 | 1 | lalala
3 | 2 |kukukuku
when i insert the value of one table to another table like this
INSERT INTO album(album_name) SELECT album_name FROM album_name
the album_id changed and i can't insert song_new table table to song table. because the relation is inaccurate now. how can i insert these two table value to two another table album and song which had already some values. i can do this by server side code by using foreach loop but can i do it in sql? can any body provide me the syntax.
Edit: here are the two table where i want to insert the values of above tables
Album
album_id | album_name
---------+-----------
1 | aaa
2 | bbb
Song
song_id | album_id | song_name
1 | 1 | old_song1
2 | 2 | old_song2
3 | 2 | old_song3
If you have already transferred your albums, you have to use the album name as a pivot..
Insert into song_new(album_id, song_name) (select a.album_id, c.song_name from song c join album b on b.album_id=c.album_id join album_new a on a.album_name=b.album_name)
In that situation you will have problems if there are plus that one album with the same name.
It was better to increment the id in album and in song table by the result of select max(album_id) from album_newand then transfer the entire tables in the new two with insert into and select *.
NEW
If you haven't.. Then is simple..
alter table album set id_album=id_album+(select max(id_album from album_new))
alter table song set id=album=id_album+(select max(id_album from album_new))
insert into album_new(select * from album)
insert into song_new(album_id, song_name) (select album_id, song_name from song)