Adding foreign key dynamically in a database via php - php

Ok I am new in php development so I did some mistakes, didnt planned my database just started because I was so excited about my first project, SO dont judg me.. :D :D
this is my Primary database
Primary Database
and this is my Movies database,
Movies database
so I created the songs database first and stored the data in it, after that i created the movies database and movie_id is the foreign key of the id of movies database, so there are too many songs to add foreign keys in primary database, I want a php script which can insert the foreign key for me in my primary database,
I created a php script ( actually tried for several hours) but didnt succseeded
I wanted to
get movie_name from songs database
match with the movie_name of movies databse
if both movies matches
insert the id of movies database into the movie_id(foreign key) of song database
<?php
require_once ('../inc/db.php') ?>
<?php
$lang_query = " SELECT * FROM songs";
$query = "UPDATE songs SET movie_id = '$mov_id'";
$lang_run = mysqli_query($conn, $lang_query);
$mov_query = " SELECT * FROM movies";
$mov_run = mysqli_query($conn, $mov_query);
$mov_row = 1;
$lang_row = 1;
while ($mov_row = mysqli_fetch_array($mov_run))
{
$mov_name = $mov_row['movie_name'];
$mov_id = $mov_row['id'];
while ($lang_row = mysqli_fetch_array($lang_run))
{
echo $movie_name = $lang_row['movie_name'];
$movie_id = $lang_row['id'];
if ($movie_name == $mov_name)
{
mysqli_query($conn, "UPDATE songs SET movie_id = '$mov_id' where id = '$movie_id'");
}
}
} ?>
Please Help me, Thanks :)

I think you can do it by running following sql query -
update *songs* inner join *movies* on songs.movie_name=movies.movie_name set songs.movie_id=movie.id

I honestly think that before you worry about trying to add foreign keys based on your current schema, that you really need to revisit the schema and normalize the data. Why have the same movie name and movie slug fields in two tables? Why have movies, songs, singers, actors, categories, etc. all in the same table? These things probably all need their own tables that are related to each other.
When building your database, think in real world terms, because you are likely going to want your application users to be able to interact with the data in the database in a real world sense. To me, you would probably need the following tables at a minimum:
movies
songs
movies_to_songs (join table to express many-to-many relationship)
actors
movies_to_actors (many-to-many)
editors
movies_to_editors (many-to-many)
movie_categories
movies_to_movie_categories (if you want to treat this as many-to-many)
singers
songs_to_singers (many-to-many)
youtube_videos (a separate table where you could store all video data)
Each table would have additional columns (properties) that are specific only to a single entity of the type contained in the table. So, for example a movie table might look like
id (primary key)
name
slug
image
language
release_date
youtube_id (reference to listing on youtube_videos table)
And you might have an actors table like:
id (primary key)
name
... (sex, birthday, etc.)
And a movies_to_actors table that is just two columns with compound primary key (i.e. combinations must be unique)
movie_id (references primary key id in movie table)
actor_id (reference primary key id in actors table)
And so on across your various tables.
Just remember to think about the real world relation of one object to another and the real world properties (columns) for each of those individual objects.

Related

Use prepared statements in PHP to insert into/display from multiple MySQL tables with foreign key

I have two tables: movies and directors. The directors attribute in the movie entity is multi-valued, which is why I created the directors table with movieId as a foreign key that references the id column of the movies table.
Now, if I want to insert movies into my movies table, how do I add all the information for the movies into the movies table, as well as the name of the directors into the directors table at the same time, possibly using transactions? Also, how do I display the information from the movies table with their corresponding directors from the directors table in a HTML5 table using a while loop? I am using PHP with prepared statements.
This is what I have so far, but it's not complete:
mysqli_autocommit($connect, FALSE);
$stmtMov = $connect->prepare("SELECT id, title, plot, rating, releaseDate, language, duration, country, posterUrl, trailerUrl, imdbUrl FROM movies");
$stmtMov->execute();
$resultMov = $stmtMov->get_result();
$rowMov = $resultMov->fetch_assoc();
$movieId = $rowMov['id'];
$stmtDir = $connect->prepare("SELECT movieId, name FROM directors WHERE movieId = ?")
$stmtDir->bind_param("?", $movieId);
$stmtDir->execute();
$resultDir = $stmtDir->get_result();
$rowDir = $resultDir->fetch_assoc();
Any help would be very much appreciated.
Since you haven't added anything about insert, I'll consider only your select part.
The $rowMov will likely result in a rowset, which is nothing more than an array, which each row will have an ID value. What you should do is iterate with your rowset and generate, for every value, a query for directors entity and get the data you want. Something like:
foreach ($rowMov as $movie) {
$stmt = $connection->prepare("SELECT .... FROM directors WHERE id_movie = ?");
$stmt->bindParam("?", $movie["ID"]);
// $execution, binding results, etc.
}
With that done, you'll have an array with directors and an array with movies. If you want to simplify things on your view (considering you're using a MVC pattern), I would associate both arrays, looking for relations of directors["ID_MOVIE"] and movies["ID"], finally creating an array with both informations like and object.
You've asked two questions,
How do I insert into two tables at the same time, and
How do I display from two tables
But before I go into that, a bit of database review is in order. I would think that each movie would have one director, while each director might have many movies. I suppose the possibility for co-directors exists, too.
So for the first case, each movie must have a director:
movies
------
movie_id
director_id
title
plot, etc...
In this case, you could simply put the director's name in the movie database, but in order to list movies by director you would have to search by the actual name (and mis-spelling would make things complicated). And directors and movies are two different things, so it's better to have separate tables.
In the second case, you need a join table to have a many-to-many relationship.
movies director_movie directors
------- -------------- --------
movie_id movie_id director_id
title director_id name
So to answer your questions,
How do you insert into two tables at the same time?
You don't. First insert into whichever table stands on its own-- in the first case, directors. Then you get the last_insert_id from that table (or if the director already exists, search for the director_id). If last_insert_id is squirrely, you may have to search for what you just inserted to get the id.
Then, you take that id value and insert it into the dependent table movies along with the rest of that table's fields.
For the many-to-many case, you would do it in similar steps: 1) insert into movies 2) get the movie_id 3) insert into direcotors 4) get the director_id 5) insert ids into director_movie
How do I display the results
If there is only one director per movie, it's a simple sql query:
SELECT movies.*, directors.name FROM movies, directors where movies.director_id=directors.director_id AND movies.movie_id=?"
If you have multiple directors per movie, you'll have to loop through results:
SELECT * FROM movies WHERE movie_id=?
then make another query to list the directors
SELECT d.* from directors AS d,director_movie AS dm WHERE dm.director_id=d.director_id AND dm.movie_id=?

Storing multiple data in one field (storing data in an array in database)

I have a table called user_thoughts. The table has many columns, one of them being favourited_by.
A thought may be favourited by many different users, but I don't want to create a new row stating that this thought id has been favourited by this user.
I would rather have it that it stores multiple username's in one field. So favourited_by for example can hold data like this:
Alice, Fred, Freddy, Conor ....
All in one single row. I have tried messing around with the data types on phpMyAdmin but cannot figure out how the field can hold multiple data.
What you're asking is the wrong way to do this. You should not serialize the favorites data into a text field for either the user table or the thought table. This destroys the whole purpose of using a relational database like MySQL.
The right way to do this: create a cross-reference table between the user table and the thought table. This utilizes a many-to-many table to store a list of favorites using the primary keys of a thought row and a user row.
Your new favorite table:
CREATE TABLE IF NOT EXISTS `favorite` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL,
`thought_id` int NOT NULL,
PRIMARY KEY (`id`)
);
What this does is take the id from the user table and store it in favorite.user_id, then stores the id from the thought table in favorite.thought_id.
To add a new favorite for the user with the id of 123, for the thought with id 456:
INSERT INTO favorite (user_id, thought_id) VALUES ('123', '456');
Get the users that have marked the thought with id 456 as their favorite (using a JOIN):
SELECT u.* FROM favorite AS f
JOIN user AS u ON u.id = f.user_id
WHERE f.thought_id = 456;
And similar to the last query, get the favorite thoughts for the user with id 123:
SELECT t.* FROM favorite AS f
JOIN thought AS t ON t.id = f.thought_id
WHERE f.user_id = 123;
The ideal way to handle this is to map it to another table, however you can just store it as json.
MySQL 5.7 even includes JSON as a data type allowing easier filtering and manipulation.
https://dev.mysql.com/doc/refman/5.7/en/json.html
You can put json into any text field however if you don't need to search it, etc.

PHP + Mysql: dynamic table name from first query for execution of second query

I have three tables, the first is a table storing applications, the second is a table storing different online forms (different types of applications), the third is a table that stores actual form data:
TABLE applications=========
-applicationID (PK)
-formID (FK)
-formRecordID
====================
TABLE forms=========
-formID (PK)
-formName
-tableName (could be 'form_businessLicense','eventLicense',etc)
====================
TABLE form_businessLicense=====
-recordID (PK)
-dateSubmitted
-(a whole bunch of other data)
===============================
"formRecordID" points to "recordID" in "form_businessLicense" or "eventLicense". Since it could reference any table, it can't be a foreign key. So instead I grab the tableName from the "forms" table, then build a query to get all the application data from, say "form_businessLicense".
So I need to get data from, say, all applications plus a bit of data from the application form filled out (ex:form_businessLicense). I'm just going to paste my code (I'm actually querying all applications in a given set of IDs):
$applications = $this->selectAll(
"SELECT applicationID, formName, tableName, fieldIdentifier, formRecordID, dateSubmitted, DATE_FORMAT(dateSubmitted,'%c/%e/%Y') AS dateSubmittedFormat
FROM applications AS a
JOIN forms AS f
ON a.formID = f.formID
WHERE a.applicationID IN (".$applicationIDs.")
ORDER BY dateSubmitted ASC"
);
for($a=0;$a<count($applications);$a++){
$form = $this->select("SELECT ".$applications[$a]['fieldIdentifier']." AS identifierName
FROM ".$applications[$a]['tableName']."
WHERE recordID = ".$applications[$a]['formRecordID']
);
$applications[$a]['identifierName'] = $form['identifierName'];
}
Is there any way to merge these two queries into one so I don't have to loop over all results and run a separate query for each result? I feel like I could maybe do this with a JOIN but I'm not sure how to reference the "tableName" and "formRecordID" for use in the same SQL statement.
You need to apply join to three tables, and select count(PK) of third table while adding a group by clause for the PK of third table.
Note: PK used for Primary Key

System for keeping track of user favorites

On my website, I have a table movies and a table users
I'm trying to have an "Add to favs" button that a user can click, which will add that movie to his favorites (ajax / javascript not necessary at the moment, just php).
So what's the simplest way I could do something like that? I've thought about this but I can't seem to find a solution (all I think of is way too complicated, and in my opinion not possible).
What's your thoughts?
I don't need a ready-made script, just an idea that could get me working (although if you have an example of such script, I'd be happy to look at it).
Thanks!
This is a many-to-many relationship. A user can favorite many movies, and a movie can be favored by many users. In an RDBMS, you represent a many-to-many relationship with a third table. I call this an intersection table but it goes by other names too.
Create a table with two columns. The columns are both foreign keys, referencing movies and users, respectively.
CREATE TABLE Favorites (
user_id INT NOT NULL,
movie_id INT NOT NULL,
PRIMARY KEY (user_id, movie_id),
FOREIGN KEY (user_id) REFERENCES Users(user_id),
FOREIGN KEY (movie_id) REFERENCES Movies(movie_id)
);
When a user chooses to favorite a movie:
INSERT INTO Favorites (user_id, movie_id) VALUES (?, ?)
When a user decides they don't like a movie any longer, delete the corresponding row:
DELETE FROM Favorites WHERE (user_id, movie_id) = (?, ?)
To get the set of movies favored by a given user:
SELECT movie_id FROM Favorites WHERE user_id = ?
To get the set of users who favor a given movie:
SELECT user_id FROM Favorites WHERE movie_id = ?
Regarding one of your comments:
You shouldn't make the "Add to favorite" a link. Indexers like Google will follow links, and then before you know it, every user has favorited every movie.
The general best practice is that read-only operations can be GET requests, while operations that write to the database can be POST requests. This means that you need to use a <form> element to submit POST requests, not an <a href="..."> element.
Add a third table:
CREATE TABLE user_favorites (
user_id INT NOT NULL,
movie_id INT NOT NULL,
PRIMARY KEY (user_id, movie_id),
FOREIGN KEY user_id REFERENCES users (user_id),
FOREIGN KEY movie_id REFERENCES movies (movie_id)
)
This is called an intersection table or join table, as it joins rows in the users table to rows in the movies table (as you see, each column is a foreign key). It is also defines a many-to-many relationship, because one user can like many movies and one movie can be liked by many users.
When you go to add a favorite movie for a user, all you have to do is insert a row in this table with the ID of the user and the ID of the movie:
INSERT INTO user_favorites(user_id, movie_id) VALUES([user ID], [movie ID])
To see what movies a user has favorited:
SELECT movie_id FROM user_favorites WHERE user_id = [user ID]
You will need to create a new table:
user_favorite_movies
--------------------
ID (primary key)
userID (foreign key)
movieID (foreign key)
date
Then when the user clicks the 'Add Favorite' button, you just insert a new row into user_favorite_movies with the users ID from the user table, the movie id from the movie table, and the date it was added (good for sorting later).
Hope this helps!
Best,
-Eric
You could create a table favourites with three columns, id, mid and uid. To add a favourite:
INSERT INTO favourites (mid, uid) VALUES (3, 5)
To search for favourites of one user:
SELECT * FROM favourites WHERE uid = 7
To search for people who favourited one movie:
SELECT * FROM favourites WHERE mid = 9
So far as I can see, you'll still need to use JavaScript or Ajax to do the post, unless you want to refresh the page every time thet mark/unmark a favorite, and also to add/remove the new favorite indicator in place at the same time.
Or am I missing something?

Why is my Update command updating all of the fields that have the same ID?

Using the update command, I want to change the type_name for a specific entry in the database, but it is changing the type_name for all the entries with the same type_id.
I need it to only change that individual entry's type_name, and not the type_name that is associated with all the entries with the same type_id.
I have an update query:
$sql = 'UPDATE photos
LEFT JOIN types
ON photos.type_id = types.type_id
SET photos.photo_title = $_POST['photo_title'],
types.type_name = $_POST['type_name']
WHERE photos.photo_id = 3';
Here's the form I'm using:
<form name="form1" method="post" action="">
<input name="photo_title" type="text" value=""/>
<textarea name="type_name"></textarea>
<input type="submit" name="update" value="Update entry" />
</form>
Here's my database structure:
TABLE photos
photo_id PRIMARY KEY
photo_title
type_id FOREIGN KEY
TABLE types
type_id PRIMARY KEY
type_name
What is happening is that your join is producing the wrong set of data. You're joining the photos and types on type_id.
Now what you seem to be describing is that the types column may contain multiple rows with the same type___id. What does this mean? It means that your join will produce multiple pairs of (photos,types) for each photo (specifically, for each photo, the join will produce n rows, where n is the number of rows in types having the same type_id as the photo).
As for how to fix this, you should take a look at your database design. You seem to expect a unique row in types for each photo. How is this relationship expressed? That will enable you to get a proper ON clause for your join.
UPDATE
After looking at the table structure, it seems your database is expressing things slightly differently. As it stands you can have multiple photos with the same type (i.e. their typeid in the photos table is the same). Thus it is a bit meaningless to speak of changing the typename of just one such photo. You're merely updating the typename for a particular type, that happens to be the type of the photo whose name you were also updating.
Now what exactly are you trying to achieve, here?
If you are trying to re categorize a particular photo, then you instead want to either create a new entry in the types table and point your photo to that new record, or find an existing photo with a matching name and point the photo at that record. (I presume you already have such code in your photo insertion logic. This should be similar)
If you are trying to update the type description for a photo and all other photos with that type, then what you have will work just fine.
I'm surprised that MySQL allows this, but it looks like you're updating the name in the type table. You're probably looking to update the type_id of a single row in the photos table.
You could do that like this:
UPDATE photos
SET photos.photo_title = $_POST['photo_title'],
photos.type_id = (
select type_id
from types
where type_name = $_POST['type_name']
)
WHERE photos.photo_id = 3
Or alternatively:
UPDATE photos
LEFT JOIN types ON types.type_id = $_POST['type_name']
SET photos.photo_title = $_POST['photo_title'],
photos.type_id = types.type_id
WHERE photos.photo_id = 3
Before you run this query, you could make sure the type_name exists:
REPLACE INTO types (type_name) VALUES ($_POST['type_name'])
I need it to only change that
individual entry's type_name, and not
the type_name that is associated with
all the entries with the same type_id.
This is your fundamental problem. There's only ever going to be one record in the types database per typeid, so when you alter it, it effectively alters it for every photo that references that typeid.
If you need to store a different type_name for every photo, just create a column in the photos table and store it there.
The other way to do this is to create a new record in the types table each time a type_name is edited - possibly doing some checking to see whether any other photos are also using that typeid (if not you can safely update the existing record). But you have to implement code that does this for yourself.
If more than one row is being updated then you are not using a unique key to update the tables. It is difficult to understand the relationship of the tables but it seems to be a 1:M relationship one type can be appended to many photos?
If so then updating the photos table using the type_id in the WHERE clause will obviously update more than one table. Use only primary keys thats are unique to update if you want to update a specific row.
You must specify the relationships of the tables if you want a decent solution :)
$sql = 'UPDATE photos
LEFT JOIN types
ON photos.type_id = types.type_id
SET photos.photo_title = $_POST['photo_title'], types.type_name = $_POST['type_name']
WHERE photos.photo_id = 3 LIMIT 1';
On a side note, you shoule be doing
$photo_title = escape_function( $_POST['photo_title'] )
$type_name = escape_function( $_POST['type_name'] )
and wrapping the varialble names in ' ' in your query string.

Categories