How can I display the users friends correctly on the users and friends side using my MySQL tables? My current code screws this up.
Users Friends Table
CREATE TABLE users_friends (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
user_id INT UNSIGNED UNSIGNED NOT NULL,
friend_id INT UNSIGNED NOT NULL,
friendship_status TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
date_created DATETIME NOT NULL,
PRIMARY KEY (id),
KEY user_id (user_id),
KEY friend_id (friend_id)
);
Users Table
CREATE TABLE users (
user_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
username VARCHAR(255) NULL,
avatar VARCHAR(255) NULL,
password CHAR(128) NOT NULL,
PRIMARY KEY (user_id),
UNIQUE KEY (username)
);
My Current MySQL Code
SELECT users.*, users_friends.*
FROM users
INNER JOIN users_friends ON users.user_id = users_friends.friend_id
WHERE (users_friends.user_id = '" . $user_id . "'
OR users_friends.friend_id = '" . $user_id . "')
AND users_friends.friendship_status = 1
GROUP BY users_friends.date_created
Try this query. This should give you all friends for a particular user based on your database relationship.
SELECT A.user_id, A.friend_id, B.username, B.avatar
FROM users_friends AS A
INNER JOIN users AS B
ON A.friend_id = B.user_id
AND A.user_id = #userToBeSearched
UNION
SELECT A.friend_id, A.user_id, B.username, B.avatar
FROM users_friends AS A
INNER JOIN users AS B
ON B.user_id = A.user_id
AND A.friend_id = #userToBeSearched
Note : I have removed the Group By clause for now because
I am afraid i do not quite understand your schema enough to make sense of why you would be grouping rows only by date_created
Adding the grouping clause will involve making another nested table as you will not be able to select columns not in the Group Clause.
Data used to test:-
Table : user
user_id |username| avatar | password
1 A AAAA
2 B BBBB
3 C CCCCC
4 D DDDDD
Table : user_friends
id | user_id | friend_id | friendship_status | date_created
1 1 2 1 Friday, October 22, 2010 3:09:44 PM
2 2 3 1 Friday, October 22, 2010 3:43:18 PM
3 2 4 1 Friday, October 22, 2010 3:43:26 PM
Related
first of all this is my first time posting a question here. If my question is already asked and answered, please provide me with the links to that question because even i don't know how to properly ask this.
so i have a table with records like this.
ID ITEM_ID DATE OUT IN
1 1002 2019-01-20 1 NULL
2 1002 2019-01-22 NULL 2
3 1004 2019-01-23 4 NULL
4 1007 2019-01-23 4 NULL
5 1002 2019-01-24 1 NULL
6 1004 2019-01-26 NULL 13
7 1003 2019-02-03 NULL 35
how can i select it to look it like this in mysql?
ITEM_ID DATE_OUT OUT DATE_IN IN
1002 2019-01-24 1 2019-01-22 2
1003 - - 2019-02-03 35
1004 2019-01-23 4 2019-01-26 13
1007 2019-01-23 4 - -
what i'm trying to do is more like concate from multiple row of same ITEM ID into 1 latest date of IN and latest date of OUT in 1 row
edit : i've add more data set for more clarification of what i'm trying to achieve.
thank you very much to anyone that have been helping me.
SELECT
a.item_id,
b.date AS date_out,
b.out,
a.date AS date_in,
a.in
FROM (SELECT item_id, date, in FROM your_table WHERE in IS NOT NULL) a
INNER JOIN (SELECT item_id, date, out FROM your_table WHERE out IS NOT NULL) b
ON b.item_id= a.item_id
Yoy can try with a left Join
SELECT a.id,a.item_id,b.date as date_out,`b.out` as 'out',a.date_in as date_in,`a.in` as 'in'
from table1 a left join table1 b
on item_id=item_id and `a.in` is not null and `b.out` is not null
If the table is called dta, then this would be:
SELECT dta_out.ID,dta_in.ITEM_ID,dta_out.`DATE` DATE_OUT, dta_out.`OUT`, dta_in.`DATE` DATE_IN, dta_in.`IN` FROM dta dta_in
INNER JOIN dta dta_out
ON dta_in.ITEM_ID=dta_out.ITEM_ID
WHERE NOT dta_in.`IN` IS NULL AND NOT dta_out.`OUT` IS NULL
I used the following table create:
CREATE TABLE `dta` (
`ID` int(11) DEFAULT NULL,
`ITEM_ID` int(11) DEFAULT NULL,
`DATE` date DEFAULT NULL,
`OUT` int(11) DEFAULT NULL,
`IN` int(11) DEFAULT NULL
)
first of all you have your table created wrong, make it like this
CREATE TABLE `your_database_name`.`new_table_name` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`item_id` INT(10) NULL,
`date_in` DATETIME NULL,
`date_out` DATETIME NULL,
`out` INT(10) NULL,
`in` INT(10) NULL,
PRIMARY KEY (`id`));
you should store the dates separately so you can select them more easy, and the query to show what you want is:
SELECT id, item_id, date_out, out, date_in, in from new_table_name;
To select the date you want from your table is going like this:
SELECT ID, ITEM_ID, (SELECT DATE FROM table_name WHERE OUT IS NOT NULL) AS
DATE_OUT, OUT, (SELECT DATE FROM table_name WHERE IN IS NOT NULL) AS DATE_IN, IN
from table_name
this select above is on your specific table with your specific 2 rows, please create the table as i posted at the begining of answer, that will make your life easier(i gave you the select aswell)
You can use this query to fetch the desired result:
SELECT DISTINCT
item_id,
(SELECT max(`date`) FROM items WHERE `out` = 1 AND item_id = 1002) DATE_OUT,
MAX(`OUT`) `OUT`,
(SELECT max(`date`) FROM items WHERE `IN` = 2 AND item_id = 1002) DATE_IN,
MAX(`IN`) `IN`
FROM items
Here is the SQL fiddle
SQL Query
I have this working fine(I'm a relatively new coder) as long as there is 1 vote. How can I get other users to vote? code below:.
SELECT
b.id,
b.image_1_file,
b.your_name,
b.your_votes,
b.image_2_file,
b.battling_with_name,
b.battling_with_votes
FROM
battles b left outer join
votes v
on
b.id = v.battle_id
where
v.battle_id is null
order by
rand()
limit 1
and I tried:
SELECT
b.id,
b.image_1_file,
b.your_name,
b.your_votes,
b.image_2_file,
b.battling_with_name,
b.battling_with_votes
FROM
battles b
WHERE
b.id NOT IN (
SELECT
v.battle_id
FROM
votes v
WHERE
v.voters_id != '$myid'
)
order by
rand()
of course the latter will only look for b.id
other users have an id variable: $my_id
I don't want the member to see the image again after they have voted.
Thanks a lot for your help and have a blessed day!
My table structures are:
my images(to vote on) table:
id int(10) unsigned NO PRI auto_increment
image_1_file varchar(40) NO
image_2_file varchar(40) NO
your_name varchar(50) NO
your_votes int(10) NO 0
battlingwithname varchar(15) NO
battlingwithvotes int(10) NO 0
my votes(votes are stored) table:
id int(10) unsigned NO PRI auto_increment
battle_id int(10) unsigned NO
vote_type tinyint(1) unsigned NO
voters_id varchar(30)
just use not in operator, you have t ignore those id from projection who is already voted, so you have to pick up those id who voted and remove from projection by using not in note:another operator exist can also be used but i used not in my query
SELECT
b.id,
b.image_1_file,
b.your_name,
b.your_votes,
b.image_2_file,
b.battling_with_name,
b.battling_with_votes
FROM
battles b
where b.id not in( select v.battle_id from votes v)
I use Yii framework to develop a website, I want to know how to get the last 5 images orderd by create_time but not within the same album by using Yii active record and by plain SQL.
here's my albums table:
CREATE TABLE IF NOT EXISTS `tbl_album` (
`album_id` int(11) NOT NULL AUTO_INCREMENT,
`album_name` varchar(45) DEFAULT NULL,
`album_folder_name` int(11) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`create_user_id` int(11) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
`update_user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`album_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=55 ;
and here's my images table:
CREATE TABLE IF NOT EXISTS `tbl_image` (
`image_id` int(11) NOT NULL AUTO_INCREMENT,
`image_name` varchar(100) DEFAULT NULL,
`image_description` varchar(100) DEFAULT NULL,
`image_album_id` int(11) NOT NULL,
`create_time` datetime DEFAULT NULL,
`create_user_id` int(11) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
`update_user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`image_id`),
KEY `fk_image_album` (`image_album_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ;
please note that I use "create_time" for sorting images.
Again, I need a query to get the last 5 images orderd by create_time but not within the same album by Yii active record and plain SQL.
for example the last 7 images are:
a.jpg in the album 7
b.jpg in the album 5
c.jpg in the album 7
d.jpg in the album 6
e.jpg in the album 3
f.jpg in the album 4
g.jpg in the album 2
h.jpg in the album 1
I need the query result to be like the following:
a.jpg in album 7
b.jpg in album 5
d.jpg in album 6
e.jpg in album 3
f.jpg in album 4
not like the following:
a.jpg in album 7
b.jpg in album 5
c.jpg in album 7
d.jpg in album 6
e.jpg in album 3
Thanks in advance.
Try this:
SELECT
a.album_name,
i1.image_name
FROM tbl_album a
INNER JOIN tbl_image i1 ON i1.image_album_id = a.album_id
INNER JOIN
(
SELECT image_album_id, MIN(image_id) image_id
FROM tbl_image
GROUP BY image_album_id
) i2 ON i2.image_album_id = i1.image_album_id
AND i1.image_id = i2.image_id
ORDER BY a.album_name DESC
LIMIT 5;
The JOIN with:
SELECT image_album_id, MIN(image_id) image_id
FROM tbl_image
GROUP BY image_album_id
will insure that for each album, the first image will be returned. Therefore you will got only one image for each album, then LIMIT 5 will limit the result set to be only 5 albums.
SQL Fiddle Demo
Note that: The ORDER BY clause will determine which five albums will be returned by the LIMIT 5 clause. So don't expect that the albums are returned in the way they are stored as the expected result in your question, because records in the table has no specific order. They are stored as a set, and you have to specify an ORDER BY clause in your query to get them in a specific order.
Update: IF you are looking for the last created image for each album, use the MAX(creaet_time) instead like so:
SELECT
a.album_name,
i1.image_name,
date_format(i1.create_time, '%Y-%m-%d') create_time
FROM tbl_album a
INNER JOIN tbl_image i1 ON i1.image_album_id = a.album_id
INNER JOIN
(
SELECT image_album_id, MAX(create_time) LatestCreateTime
FROM tbl_image
GROUP BY image_album_id
) i2 ON i2.image_album_id = i1.image_album_id
AND i1.create_time = i2.LatestCreateTime
ORDER BY i1.create_time DESC
LIMIT 5;
Updated SQL Fiddle Demo
Update 2: For the duplicate values, use the DISTINCT keyword, or you can use the MAX(image_id) instead, since the image_id is autoincremental, like so:
SELECT
a.album_name,
i1.image_name,
date_format(i1.create_time, '%Y-%m-%d') create_time
FROM tbl_album a
INNER JOIN tbl_image i1 ON i1.image_album_id = a.album_id
INNER JOIN
(
SELECT image_album_id, MAX(image_id) LatestId
FROM tbl_image
GROUP BY image_album_id
) i2 ON i2.image_album_id = i1.image_album_id
AND i1.image_id = i2.LatestId
ORDER BY i1.create_time DESC
LIMIT 5;
Updated SQL Fiddle Demo
I find another solution to my question!
SELECT *
FROM tbl_image
WHERE image_id IN (SELECT MAX(image_id)
FROM tbl_image
GROUP BY image_album_id)
ORDER BY create_time DESC
LIMIT 5;
It gives me the same result, Without use inner join which reduce performance,
What your opinion about this solution?
SQL Fiddle
Try this and let me know what it returns,
select m.image_name,a.album_name
from tbl_album a inner join
tbl_image m on a.album_id=m.image_id
group by m.image_name,a.album_name
order by 2 LIMIT 5
user_table
user_id | username
1 | solomon
2 | muna
message table
id user_id| message
1 1 | this is my first message
2 1 | this is my seocnd message
3 2 | this is muna messgae
relationship table
leader | follower
1 | 2
|
what i want to do is a three table join to bring out muna's friend messages, currently muna is following solomon(as shown on the followers table),
so i want the display to be like this on mona homepage
Solomon "this is my my first message
----------------------------------
solomon "this is my second message"
p.s. this is just an example database, i just wanted to see how to approach the problem, and this is what i have attempted so far!
select username, message, leader
from user, message, relationship where user.user_id =notes.user_id
and user.user_id = relationship.leader and where user_id = $_SESSION['user_id']
*the session id is muna which is user_id 2
heres one way of doing it
SELECT m.message,u.username FROM relationships r, messages m,users u WHERE m.user_id = r.leader AND r.leader = u.user_id AND u.user_id = 1
Spaced out
SELECT
m.message,u.username #here you can use m.* to retrieve all data
FROM
relationships r, #Here you can define what tables you want to use
messages m, #within your query, always remember to do table_name letter
users u #this will stop ambiguity within the queries
WHERE
m.user_id = r.leader #make sure the message user id is the same as the leader id
AND
r.leader = u.user_id #same as above just making the messages be filtered to the user_id
AND
u.user_id = 1 #your overall id will be here, if this was 2 it would affect WHERE, and AND above.
Within application
$query = mysql_query('SELECT m.message,u.username FROM relationships r, messages m,users u WHERE m.user_id = r.leader AND r.leader = u.user_id AND u.user_id = ' . intval($_SESSION['user_id']));
while($row = mysql_fetch_assoc($query))
{
echo sprintf("%s: %s",$row['username'],$row['message']);
echo "\r\n--------------------------------------------";
}
This is tested and works fine on the following table structure.
CREATE TABLE IF NOT EXISTS `messages` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`message` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
INSERT INTO `messages` (`id`, `user_id`, `message`) VALUES
(1, 1, 'test'),
(2, 1, 'test 2'),
(3, 2, 'test 3');
CREATE TABLE IF NOT EXISTS `relationships` (
`leader` int(11) NOT NULL,
`follower` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `relationships` (`leader`, `follower`) VALUES
(1, 2);
CREATE TABLE IF NOT EXISTS `users` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
INSERT INTO `users` (`user_id`, `username`) VALUES
(1, 'solomon'),
(2, 'muna');
I'm not really that sure what your question is. Does this look like an answer to it?
SELECT u.username,
m.message
FROM user u
JOIN message m
ON u.user_id =m.user_id
JOIN relationship r
ON u.user_id = r.leader
WHERE u.user_id = $_SESSION['user_id']
Say I have three tables in my database:
CREATE TABLE `users` (
`user_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`username` VARCHAR(16) NOT NULL
);
CREATE TABLE `users_meta` (
`meta_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`user_id` INT NOT NULL ,
`key` VARCHAR(200) NOT NULL ,
`value` TEXT NOT NULL
);
CREATE TABLE `posts` (
`post_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`user_id` INT NOT NULL ,
`content` TEXT NOT NULL
);
The table users_meta is just a key-value store of information about users, such that we can add any piece of information we want.
Say I added a key => value pair to the users_meta table for each user where the key was "age", and the value was a number representing their age.
Given this set of circumstances, what's the best way to select the first 10 posts ordered by user age?
I like putting the condition of the join in the join itself to be clear that I want a limited join:
SELECT p.post_id, p.content
FROM users u
INNER JOIN users_meta um
ON (u.user_id = um.user_id) AND um.key = 'age'
INNER JOIN posts p
ON (p.user_id = u.user_id)
ORDER BY um.value
limit 10
If you order by user age only, you will select 10 posts of the same user (the youngest one).
I would suggest to denormalize and store age in users table directly.
Agree with #KOHb, but if that's exactly what you want, here is the query:
SELECT TOP 10 p.id, p.content
FROM users u JOIN users_meta um ON (u.user_id = um.user_id)
JOIN posts p ON (p.user_id = u.user_id)
WHERE um.key = 'age'
ORDER BY um.value