So I have a database with two tables, profile, and friends. The primary key in profile is an auto incremented int, and it is a foreign key in friends. The fields in the profile table are: id, name, age, bio, motto, email_address.
The fields in friends is: initiator_id, receiver_id, date_added.
So ultimately I am trying to make a query where I set the initiator_id and get a list of receiver_id's, and use those id numbers to get them from the profile table.
I've tried left join's, inner joins, and joins in general. Open to suggestions, and interpretations on what these types of joins are actually doing.
select friends.receiver_id, profile.name
from profile
inner join friends on friends.initiator_id=1;
I need the fields to return the receiver_id number as well as the corresponding name for that id number.
The specification is a bit unclear. Sample data and expected output would go a longs ways towards illustrating the requirements.
But my guess (and without a specification, its just a guess) is that we are after the resultset returned from this query:
SELECT f.receiver_id
, p.name
FROM friends f
JOIN profile p
ON p.id = f.receiver_id
WHERE f.initiator_id = 1
Related
I'm creating a website where the users can join certain groups. Now I need to maintain the set of users in each group and/or the set of groups that each user has joined. Since MySql doesn't support arrays, I cannot maintain say, an array of users in a group(as a field in the "groups" table) or an array of groups in a user(as a field in the "users" table). So how can I achieve this?
My current solution is to maintain a table of group-subscriptions which has fields for the userID and groupID. So when I need either of these two lists I can do,
SELECT USERID FROM SUBSCRIPTIONS WHERE GROUPID=3
or
SELECT GROUPID FROM SUBSCRIPTIONS WHERE USERID=4
This will get me the desired lists. Is this the most efficient/standard way to do this or is there a better way?
You wrote all right.
Normally there are 3 types of relations between records in relative databases:
One - one (e.g. user and profile linked via user.profile_id = profile.id)
One - many (user and messages linked via message.user_id = user.id)
Many - many
Your case is the last and it always works via a 3rd table.
For your case it can be users_subscriptions (user_id, subscription_id)
Example query to select all users with their subscriptions:
SELECT u.name, GROUP_CONCAT(s.name) as `subscriptions`
FROM users u
JOIN users_subscriptions us ON us.user_id = u.id
JOIN subscriptions s ON us.subscription_id = s.id
GROUP BY u.id
If I understand your question correctly, that is the standard way.
You've created a "pivot table" that sits between the user table and the groups table and it stores the relationships between the two. This is the way that many-to-many relationships are stored in relational databases. As you correctly stated, you can retrieve all members of a group or all groups for a member that way.
I have a problem formulating a MySQL query to do the following task, although I have seen similar queries discussed here, they are sufficiently different from this one to snooker my attempts to transpose them. The problem is (fairly) simple to state. I have three tables, 'members', 'dog_shareoffered' and 'dog_sharewanted'. Members may have zero, one or more adverts for things they want to sell or want to buy, and the details are stored in the corresponding offered or wanted table, together with the id of the member who placed the ad. The column 'id' is unique to the member, and common to all three tables. The query I want is to ask how many members have NOT placed an ad in either table.
I have tried several ways of asking this. The closest I can get is a query that doesn't crash! (I am not a MySQL expert by any means). The following I have put together from what I gleaned from other examples, but it returns zero rows, where I know the result should be greater than zero.
SELECT id
FROM members
WHERE id IN (SELECT id
FROM dog_sharewanted
WHERE id IS NULL)
AND id IN (SELECT id
FROM dog_shareoffered
WHERE id IS NULL)
THis query looks pleasingly simple to understand, unlike the 'JOIN's' I've seen but I am guessing that maybe I need some sort of Join, but how would that look in this case?
If you want no ads in either table, then the sort of query you are after is:
SELECT id
FROM members
WHERE id NOT IN ( any id from any other table )
To select ids from other tables:
SELECT id
FROM <othertable>
Hence:
SELECT id
FROM members
WHERE id NOT IN (SELECT id FROM dog_shareoffered)
AND id NOT IN (SELECT id FROM dog_sharewanted)
I added the 'SELECT DISTINCT' because one member may put in many ads, but there's only one id. I used to have a SELECT DISTINCT in the subqueries above but as comments below mention, this is not necessary.
If you wanted to avoid a sub-query (a possible performance increase, depending..) you could use some LEFT JOINs:
SELECT members.id
FROM members
LEFT JOIN dog_shareoffered
ON dog_shareoffered.id = members.id
LEFT JOIN dog_sharewanted
ON dog_sharewanted.id = members.id
WHERE dog_shareoffered.id IS NULL
AND dog_sharewanted.id IS NULL
Why this works:
It takes the table members and joins it to the other two tables on the id column.
The LEFT JOIN means that if a member exists in the members table but not the table we're joining to (e.g. dog_shareoffered), then the corresponding dog_shareoffered columns will have NULL in them.
So, the WHERE condition picks out rows where there's a NULL id in both dog_shareoffered and dog_sharewanted, meaning we've found ids in members with no corresponding id in the other two tables.
Please forgive my ignorance here. SQL is decidedly one of the biggest "gaps" in my education that I'm working on correcting, come October. Here's the scenario:
I have two tables in a DB that I need to access certain data from. One is users, and the other is conversation_log. The basic structure is outlined below:
users:
id (INT)
name (TXT)
conversation_log
userid (INT) // same value as id in users - actually the only field in this table I want to check
input (TXT)
response (TXT)
(note that I'm only listing the structure for the fields that are {or could be} relevant to the current challenge)
What I want to do is return a list of names from the users table that have at least one record in the conversation_log table. Currently, I'm doing this with two separate SQL statements, with the one that checks for records in conversation_log being called hundreds, if not thousands of times, once for each userid, just to see if records exist for that id.
Currently, the two SQL statements are as follows:
select id from users where 1; (gets the list of userid values for the next query)
select id from conversation_log where userid = $userId limit 1; (checks for existing records)
Right now I have 4,000+ users listed in the users table. I'm sure that you can imagine just how long this method takes. I know there's an easier, more efficient way to do this, but being self-taught, this is something that I have yet to learn. Any help would be greatly appreciated.
You have to do what is called a 'Join'. This, um, joins the rows of two tables together based on values they have in common.
See if this makes sense to you:
SELECT DISTINCT users.name
FROM users JOIN conversation_log ON users.id = converation_log.userid
Now JOIN by itself is an "inner join", which means that it will only return rows that both tables have in common. In other words, if a specific conversation_log.userid doesn't exist, it won't return any part of the row, user or conversation log, for that userid.
Also, +1 for having a clearly worded question : )
EDIT: I added a "DISTINCT", which means to filter out all of the duplicates. If a user appeared in more than one conversation_log row, and you didn't have DISTINCT, you would get the user's name more than once. This is because JOIN does a cartesian product, or does every possible combination of rows from each table that match your JOIN ON criteria.
Something like this:
SELECT *
FROM users
WHERE EXISTS (
SELECT *
FROM conversation_log
WHERE users.id = conversation_log.userid
)
In plain English: select every row from users, such that there is at least one row from conversation_log with the matching userid.
What you need to read is JOIN syntax.
SELECT count(*), users.name
FROM users left join conversion_log on users.id = conversation_log.userid
Group by users.name
You could add at the end if you wanted
HAVING count(*) > 0
I have a table which contains messages from both users and organizations. The table contains a field called usertype which indicates whether the message was sent by a user or an organization.
I have to join this table with two tables containing user details and organization details respectively.
How can i write a join query with thes 2 tables?
I think i can achieve this via a union, but can it be done using only joins?
Table - USER fetch : user name
Table - Organization fetch : organization name
Table Messages - entries userid , usertype.
have to get username by checking datatype
UNIONs and JOINs do very different things.
UNIONs append records onto the end of a query, JOINs add fields to the end of a record.
If your UNION query works, then I'd recommend you stick with it. If you really want to do this with JOINs, then you can do the following and alter your workflow accordingly.
SELECT message_id, message_title, user.name, corp.name
FROM group_messages
LEFT JOIN users ON
users.user_id = group_messages.user_id
AND group_messages.usertype = "1"
LEFT JOIN corp ON
corp.user_id = group_messages.user_id
AND group_messages.usertype = "0"
;
What this will do is return records with fields for user AND fields for corp. When the usertype is 1 the user fields will be populated and the corp fields will be null. When the usertype is 0 the corp fields will be populated and the user fields will be null. You'll need to write application logic to read the returned usertype and determine which set of fields to read.
Honestly though, if you do something like that you're a lot better off just making it two separate queries.
If you don't want the data for each type to be in separate fields, you shouldn't use a JOIN. If you want the data from each type to be returned in the same field, you want a UNION which you already have.
My Query using Union can it be implemented using join ?
SELECT message_id, CONCAT_WS(' ',fu.user_first_name,fu.user_last_name)
uname, user_type, message_title,message_content, posted_on
FROM
group_messages fgm JOIN users fu
ON fgm.user_type='1' AND
fu.user_id=fgm.user_id WHERE
group_id='1'
UNION
SELECT
message_id, corporate_name uname,
user_type, message_title,
message_content, posted_on FROM
group_messages fgm JOIN corporate
fc ON fgm.user_type='0' AND
fc.corporate_id=fgm.user_id WHERE
group_id='1'
I have a database of articles, which are stored in categories. For my homepage, I want to grab an article from each category (I don't care which). However, some articles are crossposted to multiple categories, so they come up twice.
I have a table called tblReview with the article fields (reviewID, headline, reviewText) and a table called tblWebsiteContent that tells the site which categories the articles are in (id, reviewID, categoryID) and finally, a table called tblCategories (categoryID, categoryName) which stores the categories.
My query basically joins these tables and uses GROUP BY tblCategory.categoryID. If I try adding 'tblReview.reviewID' into the GROUP BY statement, I end up with hundreds of articles, rather than 22 (the number of categories I have).
I have a feeling this needs a subquery but my test efforts haven't worked (not sure which query needs to contain my joins / field list / where clause etc).
Thanks!
Matt
SELECT T.categoryName, tR.headline, tR.reviewText
FROM (
SELECT tC.categoryName, MAX(tR1.reviewID) reviewID
FROM tblReview tR1 join tblWebsiteContent tWC on tR1.reviewID = tWC.reviewID
join tblCategory tC on tC.categoryID = tWC.categoryID
GROUP BY tC.categoryName) T JOIN
tblReview.tR on tR.reviewID = T.reviewID
this query will select for each category an article headline corresponding to the Max reviewId for that category (you said 'I don't care which')
Try using SELECT DISTINCT. (This will only work if your SELECT is only pulling the article ID.)
select DISTINCT reviewID