Message service query on Mysql - mysql

I have a problem which I've trying to solve for days and couldnt figure this out. Please Please help me if you have any idea or tip anything .
Im trying to make a messaging service on my website. There is a product and users will able to message under it.There will be 2 users at max. Not like a comment line. Here is the database schemes I made .
ps:
$user1 ; a person who login the website,
$user2 ; the person who posted the product
$id ; the id of posted product
>CREATE TABLE `conversation`
c_id int(11)
product_id int(11) DEFAULT NULL
user_one int(11) NOT NULL
user_two int(11) NOT NULL
time int(11) DEFAULT NULL
PRIMARY KEY (`c_id`),
KEY `user_one`(`user_one`),
KEY `user_two` (`user_two`),
KEY `product_id`(`product_id`)
CREATE TABLE `conversation_reply`
`cr_id` int(11) NOT NULL AUTO_INCREMENT,
`reply` text COLLATE utf8_unicode_ci,
`user_id_fk` int(11) NOT NULL,
`time` int(11) DEFAULT NULL
`c_id_fk` int(11) NOT NULL,
PRIMARY KEY (`cr_id`),
KEY `user_id_fk` (`user_id_fk`)
KEY `c_id_fk`(`c_id_fk`)
'CREATE TABLE `post`
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`subject` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`user_post` varchar(300) COLLATE utf8_unicode_ci NOT NULL
`time_added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`type` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
`product_img` longtext COLLATE utf8_unicode_ci NOT NULL,PRIMARY KEY (`id`)
post's id referenced to product_id in conversation table
user_id_fk referenced to id in member's table
c_id referenced to as c_id_fk in conversation_reply table
Here is the query I'm trying to do.However It doesn't properly work.
SELECT U.id,C.c_id,U.username,R.reply
FROM member U,conversation C, conversation_reply R,post P
WHERE
CASE
WHEN C.user_one = '$user1' THEN C.user_two = U.id
WHEN C.user_two = '$user2' THEN C.user_one= U.id
END
AND
C.c_id=R.c_id_fk
AND
(C.user_one ='$user1' OR C.user_two ='$user2')
AND C.product_id='$id' ORDER BY C.c_id DESC

Related

Mysql - PHP - Checking a users posts and comments likes

Would anyone be able to recommend the best way to check if a user has liked a post or comment?
I am currently building a website that has similair features to Facebooks wall.
My website will show a 'wall' of posts from people you follow that you can like or comment on.
For example, comments I have:
Comments table containing: id, user_id, text (plus other columns)
Comments Likes table: comment_id, user_id, created
This is the current query I use to get the comments and checks if user has liked it using an inner join on the likes table. It uses an IF() to return liked as either 1 or empty, which works fine:
SELECT comments.id, comments.post_id, comments.user_id, comments.reply_id, comments.created, comments.text, comments.likes, comments.replies, comments.flags, user.name, user.tagline, user.photo_id, user.photo_file, user.public_key,
**IF(likes.created IS NULL, '', '1') as 'liked'**
FROM events_feed_comments AS comments
INNER JOIN user AS user ON comments.user_id = user.id
**LEFT JOIN events_feed_comments_likes AS likes ON comments.id = likes.comment_id AND likes.user_id = :user**
WHERE comments.post_id = :post_id AND comments.reply_id IS NULL
ORDER BY comments.created DESC
LIMIT :limit OFFSET :offset
However, I realise that this will not be cacheable for anyone else as it contains the logged in users likes. There may end up being a lot of posts and so will need to introduce caching.
I am wondering what the best way to check the likes will be?
At the moment these are the solutions i can think of:
I could either select all the comments limited to say 30 at a time (cacheable)
Then loop over each result doing a fetch/count query in the likes table to see if a user has liked it.
I could do a fetch from the likes table doing a where in clause using the returned 30 id results.
Then do some sort of looping to see if the likes value matches the returned results.
Fetch all of the comments (cacheable), fetch all of a users likes (could be cacheable?), then do some looping / comparing to see if the values match.
I am just not sure what would be the best solution, or if there is some other recommended way to achieve this?
I am thinking the second approach may be best but i'm interested to see what you think?
Updates to show the table Create statements
CREATE TABLE `events_feed_comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`post_id` int(11) NOT NULL,
`reply_id` int(11) DEFAULT NULL,
`text` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
`likes` int(11) NOT NULL,
`replies` int(11) NOT NULL,
`flags` smallint(6) NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
CREATE TABLE `events_feed_comments_likes` (
`comment_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`comment_id`,`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`photo_id` int(11) DEFAULT NULL,
`email` varchar(180) COLLATE utf8mb4_unicode_ci NOT NULL,
`roles` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`roles`)),
`password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`name` varchar(80) COLLATE utf8mb4_unicode_ci NOT NULL,
`tagline` varchar(120) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`biography` varchar(2000) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`social` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`social`)),
`specialties` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`available` smallint(6) NOT NULL DEFAULT 0,
`theme` varchar(7) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`photo_file` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`following` int(11) NOT NULL,
`followers` int(11) NOT NULL,
`is_private` smallint(6) NOT NULL,
`public_key` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
`show_groups` smallint(6) NOT NULL,
`show_feed` smallint(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UNIQ_8D93D649E7927C74` (`email`),
UNIQUE KEY `UNIQ_8D93D64966F9D463` (`public_key`),
UNIQUE KEY `UNIQ_8D93D6497E9E4C8C` (`photo_id`),
CONSTRAINT `FK_8D93D6497E9E4C8C` FOREIGN KEY (`photo_id`) REFERENCES `photos` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
Instead of using If in your SQL query, consider using SQL Case to simplify the query.
CASE --
WHEN ---- THEN '----'
ELSE '---'
END
For performance:
comments: INDEX(post_id, reply_id, created)
likes: INDEX(comment_id, user_id, created)
Those improvements may eliminate the need for "caching".
Please put "filtering" in WHERE, such as AND likes.user_id = :user** and put "relations" in ON. It can matter when using LEFT, and does help a human reading the query.
If events_feed_comments_likes is a many-to-many mapping table, you may want INDEX(user_id) also.
I assume this is the query in question:
SELECT comments.id, comments.post_id, comments.user_id, comments.reply_id,
comments.created, comments.text, comments.likes, comments.replies,
comments.flags, user.name, user.tagline,
user.photo_id, user.photo_file, user.public_key,
IF(likes.created IS NULL, '', '1') as 'liked'
FROM events_feed_comments AS comments
INNER JOIN user AS user ON comments.user_id = user.id
LEFT JOIN events_feed_comments_likes AS likes ON comments.id = likes.comment_id
AND likes.user_id = :user
WHERE comments.post_id = :post_id
AND comments.reply_id IS NULL
ORDER BY comments.created DESC
LIMIT :limit OFFSET :offset

mysql count each user's number of likes ,number of tweets and number of following and followers account

I'm building a twitter-like app using node.js for fun and I have multiple tables :
users: to store users' data.
tweets: to store tweets.
likes: to store what users liked what tweet.
retweets: to store what users retweeted what tweet.
following: to store what user is following other users.
CREATE TABLE IF NOT EXISTS `following` (
`user_id` varchar(50) NOT NULL,
`followed_id` varchar(50) NOT NULL,
`date_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`,`followed_id`)
)
CREATE TABLE IF NOT EXISTS `likes` (
`user_id` varchar(50) NOT NULL,
`tweet_id` varchar(50) NOT NULL,
`date_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`,`tweet_id`)
)
CREATE TABLE IF NOT EXISTS `retweets` (
`user_id` varchar(50) NOT NULL,
`tweet_id` varchar(50) NOT NULL,
`date_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`,`tweet_id`)
)
CREATE TABLE IF NOT EXISTS `tweets` (
`tweet_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`reply_to_tweet_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`reply_to_user_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`truncated` tinyint(1) NOT NULL,
`author` varchar(30) NOT NULL,
`text` varchar(255) NOT NULL,
`media` varchar(255) NOT NULL,
`entities` json NOT NULL,
PRIMARY KEY (`tweet_id`)
)
CREATE TABLE IF NOT EXISTS `users` (
`user_id` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`email` varchar(30) NOT NULL,
`username` varchar(30) NOT NULL,
`password` varchar(255) NOT NULL,
`handelname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`account_url` varchar(255) NOT NULL,
`bio` varchar(255) NOT NULL,
`profile_pic` varchar(255) NOT NULL,
`cover_pic` varchar(255) NOT NULL,
`protected` tinyint(1) NOT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`),
UNIQUE KEY `email` (`email`),
UNIQUE KEY `username` (`username`)
)
and I want to create a new view for the users containing there information along with how many tweets
they did like, the number of users they follow, the number of users follow them and how many tweets they have created.
I want this information in one table but I tried many ways and none of them worked fine for me!
what is the proper solution for such a problem?
You may try below query -
SELECT `user_id`
,LI.LI_CNT no_of_tweets_liked
,FL.FL_CNT no_of_followers
,FL2.FL2_CNT no_of_followee
,RT.RT_CNT no_of_retweets
FROM `users` U
JOIN (SELECT `user_id`, COUNT(`tweet_id`) LI_CNT
FROM `likes`
GROUP BY `user_id`) LI ON U.`user_id` = LI.`user_id`
JOIN (SELECT `user_id`, COUNT(`followed_id`) FL_CNT
FROM `following`
GROUP BY `user_id`) FL ON U.`user_id` = FL.`user_id`
JOIN (SELECT `followed_id`, COUNT(`followed_id`) FL2_CNT
FROM `following`
GROUP BY `followed_id`) FL2 ON U.`user_id` = FL2.`followed_id`
JOIN (SELECT `user_id`, COUNT(`tweet_id`) RT_CNT
FROM `retweets`
GROUP BY `user_id`) RT ON U.`user_id` = RT.`user_id`;

Mysql selecting user friendes likes

i have these tables
posts table
CREATE TABLE `users_posts` (
`pid` INT(11) NOT NULL AUTO_INCREMENT, /*post id*/
`uid` INT(11) NOT NULL, /*user who created the post, owner*/
`created_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_date` DATETIME NOT NULL,
`post_status` TINYINT(1) NOT NULL,
`content` TEXT NULL COLLATE 'utf8_general_ci',
PRIMARY KEY (`pid`),
)
connections table
CREATE TABLE `users_connections` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_1_uid` INT(11) NOT NULL, /*user id*/
`user_2_uid` INT(11) NOT NULL, /*friend user id of user id*/
`connections_status` TINYINT(4) NOT NULL,
PRIMARY KEY (`id`)
)
likes table
CREATE TABLE `post_ups` (
`upid` INT(11) NOT NULL AUTO_INCREMENT,
`uid` INT(11) NOT NULL, /*user id who like the post*/
`puid` INT(11) NOT NULL, /*post owner user id=users_posts.uid*/
`pid` INT(11) NOT NULL, /*post id=users_posts.pid*/
`up_status` TINYINT(1) NOT NULL,
PRIMARY KEY (`upid`),
INDEX `uid` (`uid`),
INDEX `up_status` (`up_status`),
INDEX `pid` (`pid`)
)
i need to select all posts and inside the query i need to check if some of my friend has like the post i'm currently selecting and if true , i can show this post on top of other post to show more relevant content
SELECT *,IF(CHECK IF FREIND LIKED THIS POST PUID == F_UID) FROM users_posts
is this possible ??
Query must like below:
SELECT up.*,
(SELECT count(*) FROM post_ups pups
WHERE up.pid=pups.pid AND up.uid <> pups.uid/*exclude own like*/
AND EXISTS (SELECT 0 FROM users_connections uc
WHERE uc.user_1_uid=up.uid/*pups.puid*/ AND uc.user_2_uid=pups.uid)) relevance
FROM users_posts up
ORDER BY relevance DESC;

Mysql case when getting another table

I have got two tables one is log details and another is user name list.
I can get with "INNER JOIN user_tbl ON log_user_id=user_id" but also I have got a super user id is exception and this exception user isn't in the user table. I am using this user at the back ground the relation with database is level of this user like as 9999.
How can I show the super user as a name like as "Supervisory"?
Example sql:
Table structures are:
CREATE TABLE `user_list_tb` (
`user_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_name` varchar(40) COLLATE utf8_turkish_ci NOT NULL,
`user_pwd` varchar(40) COLLATE utf8_turkish_ci NOT NULL,
`user_level` int(11) NOT NULL DEFAULT '0',
`user_owner_id` int(10) unsigned NOT NULL,
`user_datetime` datetime NOT NULL,
`user_change_pwd` tinyint(1) DEFAULT NULL,
`user_pwd_try` int(3) unsigned DEFAULT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `user_name_UNIQUE` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COLLATE=utf8_turkish_ci;
CREATE TABLE `log_system_tb` (
`log_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`log_act_name` varchar(10) COLLATE utf8_turkish_ci NOT NULL,
`log_user_id` int(10) unsigned NOT NULL,
`log_datetime` datetime NOT NULL,
`log_message` varchar(256) COLLATE utf8_turkish_ci DEFAULT NULL,
PRIMARY KEY (`log_id`)
) ENGINE=InnoDB AUTO_INCREMENT=49720 DEFAULT CHARSET=utf8 COLLATE=utf8_turkish_ci;
SELECT
log_id,
log_act_name,
log_user_id,
user_name,
log_datetime,
log_message
from log_system_tb
JOIN user_list_tb
ON (log_user_id=user_id)
where log_datetime>="2016-04-01 00:00:00"
and
log_datetime<="2016-04-14 00:00:00"
order by log_id desc limit 1000;
Best regards
Mehmet
You need to use a left join because there will not be a row in the user_list that corresponds to the supervisor's logged events. Also please see the case statement below.
SELECT
log_id,
log_act_name,
log_user_id,
(case when user_id=9999 then 'Supervisory' ELSE user_name END),
log_datetime,
log_message
from log_system_tb
LEFT JOIN user_list_tb
ON (log_user_id=user_id)
where log_datetime>="2016-04-01 00:00:00"
and
log_datetime<="2016-04-14 00:00:00"
order by log_id desc limit 1000;
You can do it like this:
(case when user_id=9999 then 'Supervisory' END)

Get same IDs from Detail Table

I have 2 tables in my mysql database:
CREATE TABLE IF NOT EXISTS `RECIPES` (
`recipes_id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(50) COLLATE utf8_bin NOT NULL,
`text` varchar(2000) COLLATE utf8_bin NOT NULL,
`count_persons` int(11) NOT NULL,
`duration` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`date` datetime NOT NULL,
`accepted` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`recipes_id`),
KEY `recipes_user_fk` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=88 ;
CREATE TABLE IF NOT EXISTS `RECIPES_POS` (
`recipes_pos_id` int(11) NOT NULL AUTO_INCREMENT,
`recipes_id` int(11) NOT NULL,
`ingredients_id` int(11) NOT NULL,
`ingredients_value` int(11) NOT NULL,
PRIMARY KEY (`recipes_pos_id`),
KEY `recipe_pos_rec_id` (`recipes_id`),
KEY `recipes_pos_ingredient_fk` (`ingredients_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=58 ;
In the Recipe_Pos Table are many entries. This table shows what ingredients are used in the Recipe.
Now i want to find the recipe which contains incredients like powder and sugar:
SELECT r.recipes_id FROM RECIPES r, RECIPES_POS rp WHERE r.recipes_id = rp.recipes_id AND rp.ingredients_id =6 AND rp.ingredients_id =4
this statment is wrong because a entry in Recipe_Pos can'T contains both incredients.
Whats the right query? It should works with only 1 incredient and more
select r.recipes_id
from RECIPES r
inner join RECIPES_POS rp on r.recipes_id = rp.recipes_id
where rp.ingredients_id in (4, 6)
group by r.recipes_id
having count(distinct rp.ingredients_id) = 2