PHP Mysql select query from multiple tables - php

I have 2 tables. The parent table is learn_more and child table is reference_keys
Both tables are innodb
reference_keys has two columns:
key_id [index]
key_href
learn_more table
id [primary]
keys_id [foreign key]
page_title
page_content
What I am trying to do is get multiple links in the learn more table from the reference_keys table.
So example, learn_more table id:1, keys_id:1,3,4,8,13,25,..., page_title:Home Page: blah blah, page_content: blah blah......
The problem is that phpmyadmin will not allow me to put more than 1 id in the keys_id of learn_more.
//ERROR
//Warning: #1265 Data truncated for column 'keys_id' at row 1
I'm guessing the relation view is not setup correctly. - How do i fix this?
and on my page it shows the key_id in the echo instead of the value for the id: which is the key_href. so my page show "1" instead of the value for 1 which is a link..
Perhaps my sql query is not correct?
$SQL = "SELECT * FROM learn_more WHERE page_title = '$this_page'";

To build a many-to-many here is what you could do:
reference_keys has two columns:
key_id [index]
key_href
learn_more_to_reference_key
reference_key_id [FK to reference_keys]
learn_more_id [FK to learn_more]
learn_more table
id [primary]
page_title
page_content
Then you have essentially a 1:N on each side of the relationship. Notice that I removed the FK from the learn_more table, too.
So to grab the relationship you'd query like this:
SELECT * FROM Learn_More lm
INNER JOIN learn_more_to_reference_key lmtrk ON lm.id = lmtrk.learn_more_id
INNER JOIN reference_keys rk ON rk.id = lmtrk.reference_key_id
I believe the inner join is correct, i'm double-checking that.

If you want to have one row in learn_more correspond to multiple rows in reference_keys, you need to move the foreign key field from the learn_more table to the reference_keys table.
So instead of having a foreign key field in learn_more that points out to multiple rows of reference_keys (which, as you seem to be running into, is not supported), you have the multiple rows of reference_keys all point back to the learn_more table.
This would implement a one-to-many relationship between learn_more and reference_keys. If you need a many-to-many relationship (where each reference_key rows can be connected to many learn_more rows and vice-versa) you need to use a third table to establish a link between the two databases. See http://www.tomjewett.com/dbdesign/dbdesign.php?page=manymany.php for more information.

You're getting the keys_id because that is what is in the learn_more table. To get the key_href, you'll need to JOIN the learn_more table to the reference_keys table.
Also, #ametren is correct - you should have a many-to-many table that links your two current tables.
key_linking_table
id [primary and foreign key]
keys_id [primary and foreign key]
$SQL =
"SELECT lm.id, lm.page_title, lm.page_content, rk.key_href
FROM learn_more AS lm
LEFT JOIN key_linking_table AS klt
ON klt.id = rk.id
LEFT JOIN reference_keys AS rk
ON klt.key_id = rk.key_id
WHERE [condition]"

Related

Get values from second table using foreign keys

I am creating a fantasy football android app where getting the JSON data is done with php files and SQL. My problem involves 2 tables:
player_details
player_id (primary key)
first_name
last_name
user_team
(All id fields except PK are foreign keys linked to the player_id)
user_team_id (primary key)
goalkeeper_id
rightback_id
leftback_id
etc.
I want to be able to run a PHP script, with a simple select statement in it, that will display a user team's details. I also want to include the first and last name of the players, which are linked to the foreign keys in the user_team position id fields. However all I can do is display the user_teams details and the players_id only.
SELECT *
FROM user_team
WHERE user_id = '".$uid."'
In this case, you have to do as many JOINs as the number of positions you have for your teams.
Like,
SELECT u.user_team_name, p1.goalkeeper_name, p2.rightback_name, p3.leftback_name, ...
FROM user_team u
LEFT JOIN player_details p1 ON u.goalkeeper_id = p1.player_id
LEFT JOIN player_details p2 ON u.rightback_id = p2.player_id
LEFT JOIN player_details p3 ON u.leftback_id = p3.player_id
...
WHERE u.user_team_id = <some id>
Doable, but not really good.
Then, you may change your model, and introduce the third table, that ties the player with both team and position, like:
CREATE TABLE team_positions (
player_id INT,
team_id INT,
position TEXT,
FOREIGN KEY player_id
REFERENCES player_details(player_id)
FOREIGN KEY team_id
REFERENCES user_team(user_team_id)
);
To increase the consitancy of data, it could be further normalized by introducing the positions table, than you going to refer it in team_positions by id too.
In the meantime, user_team table would retain just the team details, like name & any other stuff you wanna put there (emblem, perhaps?), along with team id.
This way, you're going to have quite flexible structure. And that is pretty much usual the way of doing stuff in relational DB model.

Get CSV from query which involves multiple tables

I'm trying to make a query to extract elements from 2 tables, which are linked via another table.
So I have 3 tables:
authors
- id, name, book
category
- id, name, description
category-author
- id, idauthor, idcategory
Now I want to make a query to make the following output:
row: authors.id, authors.name, authors.book, category.name
I don't know what category's are linked using the 2 tables only, so I need to use the last one, the category-author table. The id's of both the author and the category are linked via that table.
I got the following query:
SELECT authors.id, authors.name, authors.book, category.name FROM category, author LEFT JOIN SELECT ??
I'm stuck at the remaining part of the query.
Also when I have this query, can I just extract a CSV with phpmyadmin?
You can get related information from different tables using table joins. Relations between tables should be specified using foreign keys (i.e. the column idcategory from category-author is presumably a foreign key that refers to primary key column category.id). In a join clause, you merely specify which tables are to be joined and on what column:
SELECT table1.col1, table2.col2
FROM table1
JOIN table2 ON table1.pkCol = table2.fkCol
This means you can't specify any SELECT or FROM clauses within a JOIN clause. The columns you wish to select from joined tables are all specified in the initial SELECT statement, and you only specify one table in the FROM clause, from which you subsequently perform the table joins.
In your case, I think this should get you started:
SELECT authors.id, authors.name, authors.book, category.name
FROM category
LEFT JOIN category-author ON category-author.idcategory = category.id
LEFT JOIN authors ON authors.id = category-author.idauthor
I'm not sure how familiar you are with foreign keys, primary keys and table joins, so I won't elaborate any more on this. I think specifying multiple tables in a FROM clause is bad practice, even if your database system still supports it (Related question).
From then on, you can easily export the results from within PhpMyAdmin, as there is an export button for every table overview, including query results.

Linking tables in mysql

I need to know how to link two tables in a php/mysql set up then rank the results?
Here is my situation.
I have a stories table:
storyid
writerid
title
story
submitdate
and a votes table
voteid
userid
storyid
vote
I store a vote up as a 1 and a vote down as a -1
I am looking for a way to join these two table then rank/sort the stories by the number of votes they recieve.
I am open to any ideas about how to do so or a different possible database schema.
I prefer to keep the names of my tables singular. It's not a "Stories" table; it's a "Story" table with multiple rows.
A vote can only be attributed to a single story, so it's a one-to-many relationship between the two. I'd put the foreign key in the votes table and let it point out the story it's associated with. Change your schema if you agree: remove the voteid from the story table and make storyid in vote a foreign key to the story table.
But with that said, perhaps you can try a query like this:
select stories.storyid, sum(vote=-1) as down, sum(vote=1) as up
from stories
inner join votes on (stories.storyid = votes.storyid)
group by stories.storyid
Corrected per ypercube's comment below.

MySQL: Understanding mapping tables

When building a category navigation system for a business directory with a many to many relationship, I understand that it is good practise to create a mapping table.
Category Table ( CategoryId, CategoryName )
Business Table ( BusinessId, BusinessName )
Category Mapping Table ( BusinessId, CategoryId )
When I join the Category table and Business table to create the mapping table would this then give me a table which contains every possible business and category relationship?
I have 800 categories and 1000 business listings. Would that then give me a table containing 800,000 possible relationships. If so how would I focus on only the relationships that exist? Would I have to go through all listings (800,000) marking them as true or false?
I have been getting really confused about this so any help would be much appreciated.
When using many-to-many relationships, the only realistic way to handle this is with a mapping table.
Lets say we have a school with teachers and students, a student can have multiple teachers and visa versa.
So we make 3 tables
student
id unsigned integer auto_increment primary key
name varchar
teacher
id unsigned integer auto_increment primary key
name varchar
link_st
student_id integer not null
teacher_id integer not null
primary key (student_id, teacher_id)
The student table will have 1000 records
The teacher table will have 20 records
The link_st table will have as many records as there are links (NOT 20x1000, but only for the actual links).
Selection
You select e.g. students per teacher using:
SELECT s.name, t.name
FROM student
INNER JOIN link_st l ON (l.student_id = s.id) <--- first link student to the link-table
INNER JOIN teacher t ON (l.teacher_id = t.id) <--- then link teacher to the link table.
ORDER BY t.id, s.id
Normally you should always use an inner join here.
Making a link
When you assign a teacher to a student (or visa versa, that's the same).
You only need to do:
INSERT INTO link_st (student_id, teacher_id)
SELECT s.id, t.id
FROM student s
INNER JOIN teacher t ON (t.name = 'Jones')
WHERE s.name = 'kiddo'
This is a bit of a misuse of an inner join, but it works as long as the names are unique.
If you know the id's, you can just insert those directly of course.
If the names are not unique this will be a fail and should not be used.
How to avoid duplicate links
It's very important to avoid duplicate links, all sorts of bad things will happen if you have those.
If you want to prevent inserting duplicate links to your link table, you can declare a unique index on the link (recommended)
ALTER TABLE link_st
ADD UNIQUE INDEX s_t (student_id, teacher_id);
Or you can do the check in the insert statement (not really recommended, but it works).
INSERT INTO link_st (student_id, teacher_id)
SELECT s.id, t.id
FROM student s
INNER JOIN teacher t ON (t.id = 548)
LEFT JOIN link_st l ON (l.student_id = s.id AND l.teacher_id = t.id)
WHERE (s.id = 785) AND (l.id IS NULL)
This will only select 548, 785 if that data is not already in the link_st table, and will return nothing if that data is in link_st already. So it will refuse to insert duplicate values.
If you have a table schools, it depends if a student can be enrolled in multiple schools (unlikely, but lets assume) and teachers can be enrolled in multiple schools. Very possible.
table school
id unsigned integer auto_increment primary key
name varchar
table school_members
id id unsigned integer auto_increment primary key
school_id integer not null
member_id integer not null
is_student boolean not null
You can list all students in a school like so:
SELECT s.name
FROM school i
INNER JOIN school_members m ON (i.id = m.school_id)
INNER JOIN student s ON (s.id = m.member_id AND m.is_student = true)
When I join the Category table and
Business table to create the mapping
table would this then give me a table
which contains every possible business
and category relationship?
Yes.
Would I have to go through all listings (800,000) marking them as true or false?
No, you need to use the ON-clause to set join-conditions.
SELECT <columns> FROM categories as c
INNER JOIN mapping AS m
ON m.CategoryId = c.CategoryId
INNER JOIN businesses as b
ON m.BusinessId = b.BusinessId
You should use mapping tables when you are trying to model a many-to-many or one-to-many relationship.
For example, in an address book application, a particular contact could belong to zero, one or many categories. If you set your business logic that a contact can only belong to one category, you would define your contact like:
Contact
--------------
contactid (PK)
name
categoryid (FK)
Category
--------------
categoryid (PK)
categoryname
But if you wanted to allow a contact to have more than one email address, use a mapping table:
Contact
--------------
contactid (PK)
name
Category
--------------
categoryid (PK)
categoryname
Contact_Category
--------------
contactid (FK)
categoryid (FK)
Then you can use SQL to retrieve a list of categories that a contact is assigned to:
select a.categoryname from Category a, Contact b, Contact_Category c where a.categoryid=c.categoryid and b.contactid=c.contactid and b.contactid=12345;
select a.categoryname
from Category a
inner join Contact_Category c on a.categoryid=c.categoryid
inner join Contact b on b.contactid=c.contactid
where b.contactid=12345;
you only put the real relationships in the mapping table. so on average fi a business is in 2 categories, then in your example, there would only be 2000 records in the mapping table, not 800,000
"When I join the Category table and Business table to create the mapping table" you don't join those two tables to create the mapping table. You create an actual physical table.

mysql multi table foreign keys? - beginner

I have 2 tables,
Table1:
id, int1, int2, int3
john,1,2,4
tim,2,3,4
pete,1,3,4
Table2:
integer,blob
1,wins
2,backtickle
3,text
4,whatever
The query I want to use is given the id I want to get the blob data from table2 associated with each of the integer columns in table1.
What is the specific query I can use here?
Sample result I am looking for would be something like:
search John returns "wins","backtickle","whatever"
search pete returns "wins","text","whatever"
I think it has something to do with foreign keys, but not sure...beginner level please! With 1 table it would be SELECT * FROM table1 WHERE id="........" but not sure with the setup i have now given above.
The structure of your database does not look optimal. You're limiting yourself to 3 items per person, and you're using columns instead of rows in order to list them. What you actually have in your data is a many-to-many relationship between Table1 and Table2. What I'd recommend is using three tables:
Persons:
name, personid
john,1
tim,2
pete,3
PersonBlobs:
personid, blobid
1,1
1,2
1,4
2,2
2,3
2,4
3,1
3,3
3,4
Blobs:
blobid,blob
1,wins
2,backtickle
3,text
4,whatever
PersonBlobs would give you the many-to-many link between Persons and Blobs.
And then the query becomes:
select Blobs.blob
from Blobs inner join PersonBlobs on Blobs.blobid = PersonBlobs.blobid
inner join Persons on PersonBlobs.personid = Persons.personid
where Persons.name = 'John'

Categories