I am writing an application that helps book exchange between users.
I am using PHP and MySQL, and I am pretty new to them both.
I have 5 tables, 3 data tables and 2 service tables:
user: with user attributes (user_id, name, birth... etc).
book: with book attributes (book_id, name, author, publisher... etc).
copy: represents actual copies of a books (copy_id, condition, comments... etc).
user_copy: describes which user holds which copy, composed out of userID and copyID.
copy_book: represents the connection of copy and book, composed out of copyID and bookID
My question is:
what is the easiest and most efficient statement for getting the
book attributes and copy attributes for each copy that a user holds?
You need to inner join all the tables that you are interested in: book, copy, user_copy, and copy_book. The SELECT statement that returns attributes on all copies held by a user may look like this:
SELECT B.bookID
, B.name
, B.author
, B.publisher
, C.condition
, C.comments
-- you may get other fields that you are interested in here..
FROM book B
INNER JOIN copy_book CB ON B.bookID = CB.bookID
INNER JOIN user_copy UC ON UC.copyID = CB.copyID
INNER JOIN copy C ON C.copyID = UC.copyID
WHERE UC.userID = <the user Id that you want>
I hope it's pretty clear what the statement does but if you have any questions, please ask.
Related
Lets guess I have 3 tables:
Table a where I have a name and email
Table b where I have a text and user (as a reference to email from table a)
Table c where I have follower and following (both references to email in table a)
Im trying to develop a simple html/php/sql web that allows me to register many users and let them post different texts while also having the chance to follow or be followed by other users (already done) and I want to give an user the possibility to display the texts from table b that he himself posted and those from the users he is following
Im seriously struggling with how to extract this information
SELECT b.text
FROM tableB as b
LEFT JOIN tableC as c
ON b.user = c.follower
WHERE b.user = "currentuser"
This is as far as I got, which only shows the texts posted by the user himself (something I can do way more simple) but I cant seem to understand how to get those from the users he is following
I hope its understandable without any photo
You first want to find all following users in table c rows where the current user is the follower. Then you want to add the current user (or alternatively always have all users follow themselves). Then you want to find all texts for those users.
So:
select b.text
from (
select following as user
from tableC
where follower="current user"
union
select "current user"
) show_users
join tableB as b on b.user=show_users.user
or if you have a tableC row where follower=following for all users, just:
select b.text
from tableC as c
join tableB as b on b.user=c.following
where c.follower="current user"
I need to pull out some data from various tables using PHP prepared statements and MySQL.
The items I need to plot the data into a graph are:
tblstudent.studentID
tblquestionnaire.questionnaireID
tblstudentAnswer.answer
The database design looks like this with my table joins.
I have attempted to use INNER JOIN's, however I cannot join tblquestionnaire into it as I do not share a key with that table and the student table or with the studentAnswer table.
Any guidance would be much appreciated in how I get those pieces of information out within an SQL query.
You are overthinking it.
to get all student Ids, with their answers and the questionaire ID.
The following query is enough.
SELECT
sta.studenID
,qq.questionnaireID
,sta.answer
FROM
studentAnswer sta
INNER JOIN
questionnaireQuestions qq ON sta.questionnID = qq.questionnID
First of all, you don't need the questionnaire table to get questionnaireID - questionnaireQuestions contains it and it can be directly linked to studentAnswer. Second of all, you don't need the students table to get studentID because studentAnswer contains it. So you can simply follow this logic:
you can get questionnaireID from questionnaireQuestions
you can link questionnaireQuestions with studentAnswer through questionID to get answer and studentID
This bring us to a simple join of two tables:
SELECT sa.studentID, qq.questionnaireID, sa.answer
FROM studentAnswer sa
INNER JOIN questionnaireQuestions qq
ON qq.questionID = sa.questionID
The point is - always look for the shortest route to extract your data. Don't involve any extra tables if it can be avoided. This is where your diagram will come in handy. Looking at it, you can see that questionnaireQuestions is "closer" (one step less to connect) to studentAnswer than questionnaire. Since it contains the data you need, it's logical to use it over questionnaire.
Now let's say you needed questionnaireName along with firstName and lastName of the student. Even though you can't directly join questionnaire to student, you can do it through questionnaireQuestions and studentAnswers. Joins can contain tables you're not selecting from - it's a mechanism of connecting data. Then you'd follow this logic:
you can get questionnaireName from questionnaire
you can link questionnaire to questionnaireQuestions through questionnaireID
you can link questionnaireQuestions to studentAnswer through questionID
you can link studentAnswer to student through studentID
This brings us to a query like this:
SELECT q.questionnaireName, s.firstName, s.lastName
FROM questionnaire q
INNER JOIN questionnaireQuestions qq ON qq.questionnaireID = q.questionnaireID
INNER JOIN studentAnswer sa ON qq.questionID = sa.questionID
INNER JOIN student s ON s.studentID = sa.studentID
I'm having a small problem making a query in MySQL.
I have the following tables:
member;
group;
member_has_group (this one has the columns id_group referes to the group id and id_member referes to member id)
I'm trying to make a query that gives me the members from a selected group. Can you help me?
I'm not familiar with join tables, but for the search i made i think thats probably one of the solutions.
Thanks in advance.
Elkas
If you know the group id
select member.* from member m
inner join member_has_group mg on m.id = mg.id_member
where mg.id_group = [x]
If you only know the group name
select member.* from member m
inner join member_has_group mg on m.id = mg.id_member
inner join group g on g.id = mg.id_group
where g.name = 'group name'
This is trival in SQL :
SELECT m.id_member, m.name
FROM member AS m
INNER JOIN member_has_group AS h ON (m.id_member=h.id_member)
WHERE (h.id_group=#my_id_group)
#my_id_group is the group id you have to give.
Yep, you need a join here.
SELECT *
FROM `member`
JOIN `group` ON member.id = group.id
JOIN `member_has_group` ON group.id = member_has_group.id
Depending on the information in your tables, you may not need the third table at all.You only need a connector table with you have a "many to many" relationship between then.
(Ignore the rest if you already know
about database normalization)
For example, if you had two tables, Authors and Books. Authors would contain fields such as Name, Publisher, Birthday, whatever is a property of the "author". Books would contain relevant "book" information. This is a "one-to-many" relationship. An author may be linked (via a field such as author_id) to several books, but a book can only have one author. You would not need a third table here.
Building on that, say you had a third table for "Character Names". This would be a list of main character names used in any of the books in the "Books" table. One of the characters happens to be named John Steele. John has a whole series of books written about him. In the Books table, several of the books may list John Steele as a character. While in the characters table, John Steele could be listed in several books. This is "many-to-many". You need a third table here. It would only have two fields. A book_id and character_id, one entry for each book that John Steele appears in.
MySql Manual on DB Normalization
I am working on a web app and I have a database with two tables. One of them is called entities and the other is activities. It is a one to many relationship where there are many entities in the activities table. The activities table has a date associated with it and I want to pull results based on certain entity id's but I only want to pull the most recent activity (by its date). So basically, I only want one return per entity. There must be a way to do this in mysql without parsing out the data with php. I want to make the app as fast as possible. Any help would be greatly appreciated.
Guessing at field names ...
SELECT
e.*, a.*
FROM
(SELECT
MAX(ActivityID) ActivityID,
EntityID
FROM
Activity
GROUP By
EntityID) maxActivity
INNER JOIN Activity a
ON maxActivity.ActivityID = a.ActivityID
INNER JOIN Entity e
ON e.EntityID = a.EntityID
Or if ID isn't always the latest and you really want date (assuming two activities can't share the same date)
SELECT
e.*, a.*
FROM
(SELECT
MAX(Date) Date,
EntityID
FROM
Activity
GROUP By
EntityID) maxActivity
INNER JOIN Activity a
ON maxActivity.Date = a.Date
and maxActivity.EntityID = a.EntityID
INNER JOIN Entity e
ON e.EntityID = a.EntityID
I would say, create a linking table through a PK / FK relationship.
So for instance:
[entities table] ------ [ent_activities] --- [activities] , especially since the two data is so intertwined.
1:M is a horrible data integrity issue and even more so when you have 10s, even hundreds of 1:M throughout.
Good luck
Suppose that in table "ab" I have the names of the students that get along from class "a" and class "b", identically I have table "ac" and "bc". What SQL query should I use in order to get all the combinations possible of students who can form groups (i.e. "get along together")? And how can i extend this to n classes?
For example: John from class a gets along with Jen from class b and Steff from class c, and Jen and Steff get along. Therefore John, Jen and Steff can form a group).
For this I would create two tables, a student table (id, name, class) and a relationship table (student1, student2). You might also want to add a class table for the time, location etc of the class.
A friendship would have two relationships (2,3) and (3,2) to describe it as two way. One way might be a follower or fan of another student.
This will scale up to a lot more than 3 classes.
Then you can use multiple joins to get friends of friends and so on to an arbitrary depth.
Here is a query to get friends of friends (fof):
SELECT fof_details.*
FROM relationships r
INNER JOIN relationships fof
ON r.student2 = fof.student1
INNER JOIN student fof_details
ON fof_details.id = fof.student2
WHERE r.student1 = '12';
There are also database engines made specifically for doing graph modeling like this.
http://openquery.com/blog/graph-engine-mkii
This query should return all students who can be in one group with John.
WITH ABC AS (SELECT AB.A, AB.B, AC.C FROM (SELECT * FROM AB
INNER JOIN BC
ON AB.B=BC.B)
INNER JOIN AC
ON (AC.C=BC.C AND AB.A=AC.A))
SELECT STUDENT FROM (
SELECT AB.B STUDENT FROM ABC WHERE AB.A='John'
UNION
SELECT AC.C STUDENT FROM ABC WHERE AB.A='John')
GROUP BY STUDENT
PS.: Written fast without any syntax check, hope you'll be able to bring this to work :)
The initial query can be satisfied by the code
select ab.a, ab.b, ac.c
from
ab inner join
bc on ab.b = bc.b inner join
ac on ac.a = ab.a and bc.c = ac.c
Stepping up to n classes will get progressively more complex as n=4 would be the same query with the additional three joins
inner join ad on ab.a = ad.a
inner join bd on bd.b = ab.b and ad.d = bd.d
inner join cd on cd.c = ac.c and ad.d = cd.d
2 classes requires 1 table and no joins,
3 classes requires 3 tables and 2 joins,
4 classes requires 6 tables and 5 joins
So we can see it getting progressively more complex as we proceed
First you don't want to have a table for each class. You are capturing the same type of information in multiple tables and this is generally considered a bad practice. You want to "normalize" your data so that the same data exists in one place.
Second, name your tables appropriately so that you understand what you are actually trying to build. Maybe you are generalizing to mask what your intentions for the actual implementations are by using "ab" in the question, but if you are doing this in your actual code it will hurt you in the long run.
It appears you need a people table with names and a friends table where you track who is friends with who:
create table people ( id int, name char(128) );
create table friends ( id int, person_id int, friend_id int );
Then you just need to have the query to get the groups:
SELECT person.* FROM friends
INNER JOIN friends grp
ON friends.friend_id = grp.person_id
INNER JOIN people person
ON person.id = grp.friend_id
WHERE friends.person_id = 42;