Delete rows from 4 tables based on one? - mysql

I'm looking for a query to delete all records from a user in the database. There is one table users:
user_id | name
one table posts
post_id | user_id | post_html
one table posts_tags
id | post_id | tag_id
one table tags
id | user_id | tag
I'm looking to delete all records linked to a user from this 4 tables...
Like
delete from tags t inner join posts_tags bt on t.id = bt.tag_id where ???
Thanks

You can do it in one statement, if you like:
delete u, p, pt, t
from users u join
posts p
on u.id = p.user_id join
posts_tags pt
on p.id = pt.post_id join
tags t
on t.id = pt.tag_id
where u.id = #YOURUSERID;

I'm agree with zerkms - you could use cascade foreign keys. But it could be written as SQL queries too, but if you have foreign keys, you have to do it in correct order, something like:
delete from posts_tags
where
tag_id in (select id from tags where user_id = <your user id>) or
post_id in (select post_id from posts where user_id = <your user id>)
delete from tags
where user_id = <your user id>
delete from posts
where user_id = <your user id>
delete from users
where user_id = <your user id>

Related

mysql join with two row into one

I have 2 tables table name is users and projects.the structure of table is:
user table
id | name | role
1 | samjad | user
2 | saneer | constructor
projects table
id | name | user_id | constructor_id |
1 | school | 1 | 2 |
How can i get all details from both table in a single row based on project table id.
i want to select
projectname username, constroctorname, user_id, constroctor_id
in a single row
You can join the user table twice - Once as users and then as constructors.
select p.name as projectname,
u.name as username,
c.name as contructorname,
p.user_id,
p.contructor_id
from projects p
left join user u on p.user_id = u.id
left join user c on p.contructor_id = c.id
where u.role = 'user' -- check if the said user has role "user"
and c.role = 'constructor'; -- check if the said constructor has role "constructor"
Do the fact you have two relation between project table and user (one for user and one for constroctor) You can use user joined for two time
select p.name, u1.username, u2.username, p.user_id, p.constroctor_id
from projects as p
inner join user as u1 on p.user_id = u1.id
inner join user as u2 on p.constroctor_id = u2.id
You can use concat() function:
SELECT CONCAT(field1, field2, field3);
https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_concat
or CONCAT_WS(separator,str1,str2,...)
Assuming there is a table called Constructor with columns name and constructor_id your query would be
select
p.name as projectname,
u.name as username,
c.name as constructorname,
u.id as userid,
c.id as constructorid
from
projects p
inner join user u on p.user_id=u.id
inner join constructor c on p.constructor_id=c.id
Use a join. You probably want an INNER JOIN:
SELECT * -- actually include only the fields you need
FROM Projects p
INNER JOIN Users u ON u.id = p.user_id
INNER JOIN Users uc ON uc.id = p.constructor_id
You'll want to join the tables on their keys. In this case something like the below:
select p.name as projectname
, u.name as username
, if(u.role='constructor',u.name,null) as constructorname
, p.user_id, p.constructor_id
from users u
join projects p
on p.user_id = u.id;

SQL Query Returning Wring values for Sum and Count

My SQL Query contains three tables the posts table, post_likes table, and comments table.
All tables are connected with the post_id primary key in the posts table. I am trying to return the content of the posts row as well the amount of likes/dislikes it has in the post_likes table, and the amount of comments. The query worked fine until I introduced the second left join and it now displays the like_count column x5 dislike_count column x5 and the new comment_count x4.
This is the query in question:
SELECT c.post_id, c.post_name, c.post_content, c.post_datetime, c.user_name, sum(p.like_count) AS like_count, sum(p.dislike_count) AS dislike_count, sum(s.comment_count) AS comment_count FROM posts c LEFT JOIN post_likes p ON c.post_id = p.post_id LEFT JOIN comments s ON c.post_id = s.post_id WHERE c.user_name = 'test' GROUP BY c.post_id
is returning the sum values:
//column | returned value | expected value
like_count | 10 | 2
dislike_count | 5 | 1
comment_count | 20 | 5
Some additional notes, the likes/dislikes are stored in the postlikes table with the structure.
post_like_id, like_count, dislike_count, post_id, user_name
The like or dislike count can only be 1 in either column the PHP handles this to ensure users cant like multiple times etc and the user_name column is the user who liked the post.
The comments table structure is as follows:
comment_id, comment_name, comment_content, comment_datetime, comment_count, post_id, user_name
The comment_count is always 1 when inserted to allow for the sum function, post_id is the id of the post for the comment, and the user_name is the user who commented.
Your joins are producing a cartesian product -- instead move the aggregation results into subqueries:
SELECT c.post_id, c.post_name, c.post_content, c.post_datetime, c.user_name,
p.like_count,
p.dislike_count,
s.comment_count
FROM posts c
LEFT JOIN (
select post_id,
sum(like_count) like_count,
sum(dislike_count) dislike_count
from post_likes
group by post_id
) p ON c.post_id = p.post_id
LEFT JOIN (
select post_id, sum(comment_count) comment_count
from comments
group by post_id
) s ON c.post_id = s.post_id
WHERE c.user_name = 'test'

MySQL order by the number of matches in an intermediate table

So I have a query that is trying to grab "related posts".
Categories have a one-to-many relationship with posts. Tags have a many-to-many relationship. So my tables look roughly like this:
posts table:
id | category_id | ... | ...
tags table:
id | ... | ...
post_tag intermediate table:
id | post_id | tag_id | ... | ...
So if I have a single Post row already, and what to grab its "related" posts. My logic is roughly that I want to grab only posts that are in the same category, but to order those posts by the amount of tags that match the original post. So another post in the same category that has the exact same tags as the original post, should be a very high match, whereas a post that only matches 3/4 of the tags will show up lower in the results.
Here is what I have so far:
SELECT *
FROM posts AS p
WHERE p.category_id=?
ORDER BY ( SELECT COUNT(id)
FROM post_tag AS i
WHERE i.tag_id IN( ? )
)
LIMIT 5
BINDINGS:
Initial Posts Category ID;
Initial Posts Tag IDs;
Clearly this is not going to actually order the results by the correct values in the sub-select. I am having trouble trying to think of how to join this to achieve the correct results.
Thanks in advance!
If I undestood your question correctly this is what you're looking for:
SELECT p.*,
Count(pt.tag_id) AS ord
FROM posts AS currentpost
JOIN posts AS p
ON p.category_id = currentpost.category_id
AND p.id != currentpost.id
JOIN post_tag AS pt
ON pt.post_id = p.id
AND pt.tag_id IN (SELECT tag_id
FROM post_tag
WHERE post_id = currentpost.id)
WHERE currentpost.id = ?
GROUP BY p.id
ORDER BY ord DESC
BINDINGS: Initial posts.id;
and you only have to specify the id of the current post in my version so you don't have to fetch the posts tags beforehand and format them suitably for an in clause
EDIT:
This should be a faster query by avoiding double joining posts, if you don't like user variables just replace all currentpostid with ? and triple-bind post_id:
set #currentpostid = ?;
select p.*, count(pt.tag_id) as ord
from posts as p,
join post_tag as pt
on pt.post_id = p.id
and pt.tag_id in (select tag_id from post_tag where post_id = #currentpostid)
where p.category_id = (select category_id from posts where id=#currentpostid)
and p.id != #currentpostid
group by p.id
order by ord desc;
Try this,
SELECT posts.*
FROM posts,(SELECT p.id,
Count(pt.tag_id) AS count_tag
FROM posts AS p,
post_tag AS pt
WHERE p.category_id = '***'
AND pt.post_id = p.id
AND pt.tag_id IN(SELECT tag_id
FROM post_tag
WHERE post_tag.post_id = '***')
GROUP BY p.id
) temp
WHERE posts.id =temp.id ORDER BY temp.count_tag desc
Where you can fill *** as you already have 1 post row

Mysql join from multiple tables

I have 3 tables
friends
posts
members
friends
========
id, to, from (user_id's), status
there are 3 status's -1 = denied, 0 = no response/new, 1 = accepted
posts
=======
p_id, user_id (same as member_id), text
members
========
member_id, f_name, l_name
If like to select the text from the post in 'posts' combine it with the users name from 'members' and only display posts where the user_id is in the 'friends' table.
I would like to know if it can be done, I've tried an IN () statement in my query which worked, but it creates a new problem with generating the csv inside the IN (). I'd perfer to do this through mysql, but if it can't be done I may use a global variable to store friend data (but then it will not be upto date or will have to be refreshed when a user gets a new friend).
As I understand it, you want to find the name and posts of all your friends, not any friend that's in the friend table at all...?
Your own user id being in $myId, this should do it (newest posts first);
EDIT: Added status check for friends
SELECT m.f_name, m.l_name, p.`text`
FROM members m
JOIN posts p
ON m.member_id = p.user_id
JOIN friends f
ON f.`to` = m.member_id OR f.`from` = m.member_id
WHERE (f.`from` = $myId OR f.`to`= $myId)
AND f.`status` = 1 AND m.member_id <> $myId
ORDER BY p.p_id DESC
Try this :
SELECT p.text,m.f_name,m.l_name FROM posts p
LEFT OUTER JOIN members m ON p.user_id=m.member_id
where p.user_id in(select id from friends);
OR
SELECT p.text,m.f_name,m.l_name FROM posts p
LEFT OUTER JOIN members m ON p.user_id=m.member_id
INNER JOIN friends f on p.user_id=f.id
If I understand correctly, you have a user_id and you want all the posts authored by "friends" of that user. This query starts at posts, joins that to friends (where the author is the "destination" of the friendship) (at which point the WHERE clause will filter out any non-friend posts), and then joins in members to fill out the author's name info.
SELECT
posts.p_id
posts.text,
CONCAT(members.f_name, " ", members.l_name)
FROM
posts
JOIN friends ON posts.user_id = friends.to
JOIN members ON posts.user_id = members.member_id
WHERE
friends.from = ?
GROUP BY posts.p_id
I added a subquery to get all your friends since I assumed that if you have these records
Friends
==================================
ID TO FROM STATUS
==================================
1 1 2 1
2 3 1 1
and your member_id = 1, your friends are 2, 3. right?
SELECT b.f_name,
b.L_name,
c.`text`
FROM
(
SELECT `to` friendID
FROM friends
WHERE `status` = 1 AND
`from` = ? -- change this to your ID
UNION
SELECT `from` friendID
FROM friends
WHERE `status` = 1 AND
`to` = ? -- change this to your ID
) a INNER JOIN members b
ON a.friendID = b.member_ID
LEFT JOIN posts c
ON a.friendID = c.user_id

How do I run a select query with count()?

account_users
-----
id | primary_key
posts
-----
post_id | primary_key
author | foreign key to account_users.id
Let's say I have 2 tables. account_users has the users. posts holds the posts.
How can I select all users where count(*) of posts are more than 5?
Try this
SELECT au.*,p.*
FROM account_users au
INNER JOIN posts p
ON p.account_users.id = au.id
GROUP BY p.post_id
HAVING count(*) > 5
#Timex
try below query.
Select au.ID from account_users au
inner join posts p on au.ID = p.author
Group By au.ID
having COUNT(p.post_id) > 5