MySQL users table and posts table - matching the ID - mysql

I'm quite new to databases so i apologise in advance if this sounds silly. Im creating a basic web application that simulates a micro blogging website. I have three tables authors, posts & comments.
The authors table is described as follows:
aId int(20) NO PRI NULL auto_increment
aUser varchar(30) NO UNI NULL
aPass varchar(40) NO NULL
aEmail varchar(30) NO UNI NULL
aBio mediumtext YES NULL
aReg datetime NO NULL
the posts table is described below:
pId int(20) NO PRI NULL auto_increment
pAuthor int(20) NO MUL NULL
pTitle tinytext NO NULL
pBody mediumtext NO NULL
pDate datetime NO NULL
I understand the basics of relationships, but could i ask, if on my web application i want to display the posts and include who posted them, is there a way of doing this so the result set will show the actual username, rather than the numeric ID ? each time a post is created i capture the users ID, so every post created is by a valid user ID and the post table records the user ID of the person who created it, but when viewing the posts in a select query it shows the numbers and not the names associated with them in the authors table. us there a query i could use to do this or a way of doing it so when use a select * from authors, it shows the usernames rather than the user ID.
Thank you guys.

I think you are looking for a SQL query:
SELECT pTitle, pDate, aUser
FROM posts
LEFT JOIN authors ON aId=pAuthor
ORDER BY pDate DESC
After the SELECT you tell the MySQL what columns you want to see, with the LEFT JOIN you connect the tables together (by aId and pAuthor) and with ORDER BY you tell the mysql to give them to you ordered by date starting from newest pDate DESC (highest date first)
SELECT posts.*, authors.aUser
FROM posts
LEFT JOIN authors ON aId=pAuthor
WHERE pTitle LIKE "%news%"
ORDER BY pDate DESC, aUser ASC
to see the author's name when searching for posts with title containing "news" sorted from the newest posts, and in case two posts having the same timestamp, show them ordered by users name (Adam will go before Zachariash)
In case you do not need to see more than title, date and users name, use the 1st row from the first query above

Related

SQL select latest message of every conversation received AND sent

This question SQL select only rows with max value on a column doesn't solve my problem although it has been marked as duplicate.
It assumes my columns from_id and to_id are primary keys, when they don't have such constraint (see code provided bellow). If they were primary keys, I couldn't store my messages in the same table. As a result the SQL query of this answer prints all duplicates multiple times, which is not what I want. Please see expected behaviour bellow.
Expected behaviour : I need to select the latest message from all conversations, regardless of whether the user is only sender, recipient, or both. Each conversation/thread should only be displayed once.
Example : when querying this table, my SQL statement should only output msg3 and msg4, ignoring all the previous messages John and Alice exchanged.
Here is the closest query I could write. Problem is this query only selects conversations where user received a message. I'm stuck adding conversations where user is only sender (he didn't get any reply) to the selection.
SELECT * FROM messages where `to_id` = '1' GROUP BY `from_id` ORDER BY `send_date` ASC
Here are users and messages tables:
CREATE TABLE users (
id INT(11) AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(128) NOT NULL
);
CREATE TABLE messages (
id INT(11) AUTO_INCREMENT PRIMARY KEY,
to_id INT(11) NOT NULL, //recipient id to match to current user id
from_id INT(11) NOT NULL, //sender id to match to current user id
send_date DATETIME DEFAULT CURRENT_TIMESTAMP,
content TEXT
);
Question: How can I do this using a single SQL query ? Or should I change my data structure using three tables instead of one ?
I would first get the ids. You can do this using least() and greatest():
select least(m.to_id, m.from_id) as id1,
greatest(m.to_id, m.from_id) as id2, max(m.id) as max_id
from messages m
group by id1, id2;
You can then get the complete information about the message by joining back:
select m.*
from messages m
where m.id in (select max(m.id) as max_id
from messages m
group by least(m.to_id, m.from_id), greatest(m.to_id, m.from_id)
);
Note: In older versions of MySQL, putting the subquery in the from clause and using join is much more efficient.

MySQL - get rows with same ID but different specific values on another column

I know the title isn't very helpful, part of the reason I'm having trouble figuring this out on my own is I can't figure out how to word it, so I can't google it.
Anyway, I'm making a Netflix style website with movies and TV shows ripped from my DVD collection. It's a LAMP stack running off my Raspberry Pi. I want to have the option to search by genre by selecting genres from a bunch of check boxes. I want it to work so that if I check "horror" and "comedy", the search results only return movies/TV shows that have BOTH those genres, not either/or.
So I have a couple MySQL tables, THR_MOVIE, THR_SHOW, and THR_GENRE. The structures of THR_MOVIE and THR_SHOW aren't really important for this question, just know that each movie/TV show takes up just one row and has a unique ID. Here's the structure of THR_GENRE:
CREATE TABLE `THR_GENRE` (
`media_id` INT(7) UNSIGNED NOT NULL,
`genre` VARCHAR(255) NOT NULL,
`media_type` ENUM('movie','show') NOT NULL,
`date_added` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`media_id`, `genre`, `media_type`))
Obviously if media_type is 'movie', then media_id is a THR_MOVIE ID and not a THR_SHOW ID. Some example data from the genres table might look like this:
row 1: media_id=12, genre='horror', media_type='movie'
row 2: media_id=12, genre='comedy', media_type='movie'
So how would this query work? I need to get the movie data, so I need to join THR_MOVIE with THR_GENRE to get the movies, then do the same with THR_SHOW and THR_GENRE to get the TV shows.
You might use left outer join:
select
*
from
THE_GENRE g
left outer join
THR_MOVIE m
on m.id = g.media_id
and g.media_type = 'movie'
left outer join
THR_SHOW s
on s.id = g.media_id
and g.media_type = 'show'
Query will return columns for both movie and show tables. Code which consume this query result will need to check media_type value and use movie table columns if type is 'movie' or show table columns if type is show.
Thanks for the response, but I just figured it out myself.
select *
from THR_GENRE
where (genre='horror'
or genre='comedy')
and media_type='movie'
group by media_id
having count(*)=2
Obviously my PHP script will have to create the query string with count(*)=X, where X is some variable holding the number of genres searched for.

combine two rows from one table together based upon join to a second table in MySQL

Hello I have two tables in MySQL. The first table is called users it has a column ID that relates to table 2 which is called family. The family table has two columns, familyID and userID. Basicly what I want to do is concatenate a first name column in the users table where familyIDs are the same.
So if John(userID 1) and Jane(userID 2) have a familyID of 123 it returns a result of 'John and Jane'.
Is this posible with SQL or do I need another programming language like C# and have a logical check?
Updated info:
Users Table:
/Column Information/
Field Type Key
----------------- ----------- ------
id int(11) PRI
username varchar(30)
fName varchar(50)
lName varchar(50)
Family Table:
/Column Information/
Field Type Collation Null Key
ID int(11) (NULL) NO MUL
userID int(11) (NULL) YES MUL
/Index Information/
Table Non_unique Key_name Seq_in_index Column_name
family 1 familyUser 1 userID
family 1 familyID 1 ID
Ive tried several joins and even a self join but most of them return data just not what Im looking for as it repeats all the first names join together.
Please let me know if you need any additional info.
I was able to figure it out with the help of a few other posts here that i was able to find and some tweaking.
This is what I came up with:
SELECT
REPLACE(GROUP_CONCAT(IF(f.id = f.id,u.fname, NULL)), ',', ' & ') AS 'First Name'
FROM users AS u
JOIN family AS f
ON u.id = f.userid
GROUP BY f.id;
Thank you for the in site to my problem!
You can use an INNER JOIN to use the family columns in your conditions:
SELECT users.first_name
FROM users
INNER JOIN family
ON family.userID=users.ID
WHERE family.ID=:familyId;
Edit:
Soory I am an PHP guy, so the :familyId is supposed to be replaced for the actual familyID you are searching for.
When joining tables you can also use columns from joined tables for conditions so with the above query only results that has a corrosponding row in the family table with the supplied familyID will be selected.

How to get 3 parameters from 3 different tables in one query - SQL

I have these tables:
CREATE TABLE User(
Username varchar(15) NOT NULL,
Name varchar(20) DEFAULT '',
Surname varchar(20) DEFAULT '',
Email varchar(30) DEFAULT '',
City varchar(20) DEFAULT '',
Description varchar(1000) DEFAULT '',
userID INTEGER NOT NULL,
Primary key(Username, userID),
Foreign key(userID) references Followers(userID)
);"
CREATE TABLE Followers(
userID INTEGER NOT NULL,
usernameFollower varchar(15),
Primary key(userID),
Foreign key(usernameFollower) references User(Username)
);"
CREATE TABLE Post(
Username varchar(15) NOT NULL,
userID INTEGER NOT NULL,
Date DATETIME NOT NULL,
Message VARCHAR(500) NOT NULL,
Primary key(Username, Date),
Foreign key(Username) references User(Username)
);"
I need to get with a query a list with all the users in User, and for each user the date of the latest post they made and the number of followers they have.
For example, the output have to be like this:
USERNAME LATEST POST FOLLOWERS
user1 2011/11/11 18:30:11 5
user2 2011/10/05 17:30:00 1
user3 2010/05/11 18:30:11 90
user4 2011/11/11 18:30:11 5
I can't figure how to make it..I presume for the count of the followers I need to use COUNT(), but how can I link it to the latest post of the user? Is possible in just one query? Or do I need to use views?
Thanks in advance, best regards.
You need to join across all 3 tables via the userID. You can then select the latest post date by grouping by user id. Originally, I also joined onto the Followers table, but this has an unintended side-effect, so...
Something like:
SELECT U.Name AS UserName,
MAX(P.Date) AS LatestPost,
(SELECT COUNT(F.userNameFollower) FROM Followers WHERE userID = U.userID) AS FollowerCount
FROM User U
INNER JOIN Post P ON (U.userID = P.userID)
GROUP BY U.UserID
Should work.
Please note that my query is assuming that a user has posted. If they haven't then change the INNER JOIN to a LEFT JOIN.
The reason the original query doesn't work is that it matches a row in Post for each user, and a row in Followers for each user - thus multiplying the number of results. Instead, we can use a subquery to select the count of followers with the matching userid in the User table.
HOWEVER... this only counts the total number of followers a user has, not the number of followers for a post. The reason for this is because you have only linked a follower to a user. You'd also need to have a relationship between Follower and Post.
You can do this in a number of ways; you can create a PostFollower table consisting of PostId and UserId (so you can see which user has followed each post) or you can add a PostId to the Follower table, and store the follower userId and the PostId, allowing you to store which user followed which posts.
It will be something like below.Please do necessary change
select u.Username,max(p.Date) as latest_post,count(f.userId) as totalfollowers
from users as u
left join post as p on u.userId=p.userId
left join followers as f on u.userId-f.userId
order by p.date desc
group by u.userId

MySQL query for "Recent Activity"

I'm creating a site where users can create photo albums, create events, upload videos etc. What I want to do is make a list of a given user's recent activity. Here's a small outline of my tables:
**videos**
id
user_id
uploaded
**albums**
id
user_id
created
updated
**comments**
id
user_id
date
Of course there are more fields in the table, and also more tables, but these should be enough to help me construct a query.
Now what I want to be output is a date, and the id for a given activity with these fields:
user_id, video_id, album_id, comment_id, date
Of course only one of the ID fields should be chosen, the rest should just be null, and the date should come from "uploaded" for videos, "updated" for albums and "date" for comments. The user_id should be selected in the query in a where statement so you get activity for a given user.
I've tried to construct this query but failed, quessing that COALESCE should be used for choosing the different timestamps but I just can't get around it.
Something like this?
(select user_id, id as video_id, NULL as album_id, NULL as comment_id, uploaded as date from videos)
UNION
(select user_id, NULL, id, NULL, uploaded from albums)
UNION
(select user_id, NULL, NULL, id, date from comments)
You can apply an ORDER BY clause after the whole thing, but WHERE conditions much be put inside the parenteses of each separate SELECT.