I have 3 tables, user_tag, article_tag, article_ignored. I want to fetch only those articles of user_id = 48 for which at least one article tags matches with user tag. I am stuck in this since long time and don't have any idea how to achieve this.
The table structure is as follows:
article_ignored table
id | user_id
1 | 48
2 | 48
3 | 48
article_tag table
id | article_id | tag_id
1 | 1 | 1
2 | 1 | 5
3 | 1 | 7
4 | 2 | 2
5 | 2 | 8
6 | 3 | 3
7 | 3 | 2
user_tag table
id | user_id | tag_id
1 | 48 | 2
2 | 48 | 3
Required output:
article_ignored
id
2
3
You can use NOT EXISTS:
SELECT id, user_id
FROM article_ignored AS ai
WHERE EXISTS (SELECT 1
FROM article_tag AS at
JOIN user_tag AS ut ON at.tag_id = ut.tag_id
WHERE ai.id = at.article_id)
Demo here
Related
I have the following table:
+----+-------------+-----------------+-----------+----------------+
| id | link_id[FK] | category_id[FK] | parent_id[FK] | sort_order |
+----+-------------+-----------------+-----------+----------------+
| 1 2 1 1 1 |
| 2 2 133 1 2 |
| 3 3 2 2 1 |
| 4 3 200 2 2 |
| 5 3 333 200 3 |
| 6 4 1 1 1 |
| 7 5 3 3 1 |
| 8 5 133 3 2 |
| 9 5 223 133 3 |
| 10 5 456 223 4 |
+-----------------------------------------------------------------+
I need to be able to SELECT all rows with the same link_id, but using the category_id as the condition. So here is the example result I am looking for.
+----+-------------+-----------------+-----------+----------------+
| id | link_id[FK] | category_id[FK] | parent_id[FK] | sort_order |
+----+-------------+-----------------+-----------+----------------+
| 1 2 1 1 1 |
| 2 2 133 1 2 |
| 7 5 3 3 1 |
| 8 5 133 3 2 |
| 9 5 223 133 3 |
| 10 5 456 223 4 |
+-----------------------------------------------------------------+
I've tried this query, but it only returns the rows that equal category_id 133.
SELECT *
FROM table a
WHERE (a.object_id,a.category_id) IN (
SELECT b.link_id,b.link_id
FROM table b
WHERE b.category_id = 133
AND a.link_id = b.link_id
) ORDER BY a.sort_order
I've also tried a SELF JOIN, which is basically what I need, but then I get separate columns and I need them combined like above.
You first need to get the link_ids from the table where category_id = 133, then query the table for all the rows with that link_id.
SELECT * FROM `table`
WHERE link_id IN (
SELECT link_id FROM `table`
WHERE category_id = 133
)
ORDER BY link_id, sort_order
DEMO: http://sqlfiddle.com/#!9/67eb4/5
You should also be able to do this with a "self join", too:
SELECT a.* FROM `table` a
JOIN `table` b ON a.link_id = b.link_id
WHERE b.category_id = 133
ORDER BY a.link_id, a.sort_order
DEMO: http://sqlfiddle.com/#!9/67eb4/6
I have 4 tables:
users (id, name, email);
id | name | email
1 | ABC | abc#gmail.com
2 | XYZ | xyz#gmail.com
3 | AAA | aaa#yahoo.com
papers(id, title, content, created_by)
id | title | content | created_by
1 | This is title 1 | This is content 1 | 1
2 | This is title 2 | This is content 2 | 1
3 | This is title 3 | This is content 3 | 3
4 | This is title 4 | This is content 4 | 1
5 | This is title 5 | This is content 5 | 3
6 | This is title 6 | This is content 6 | 2
rating(id, paperId, star)
id | paperId | star
1 | 1 | 2
2 | 2 | 4
3 | 3 | 4
4 | 2 | 2
5 | 1 | 3
comments(id, paperId, msg)
id | paperId | msg
1 | 1 | abcd
2 | 2 | xxxx
3 | 2 | yyyy
4 | 3 | zzzz
5 | 1 | tttt
6 | 4 | kkkk
I want to get fields: papers.id, papers.title, papers.content, users.name,
AVG(rating.star), COUNT(comments.msg)
And I execute a query like:
SELECT papers.id, papers.title, papers.content, users.name,
AVG(rating.star) AS avg_star , COUNT(comments.msg) AS num_of_cmt
FROM papers
JOIN users ON users.id = papers.created_by
LEFT JOIN rating ON rating.paperId = papers.id
LEFT JOIN comments ON comments.paperId = papers.id
WHERE papers.id = 1
Then result is false at "num_of_cmt" field:
id title content name avg_star num_of_cmt
1 This is title 1 This is content 1 ABC 2.5000 4
Above, 'num_of_cmt' is 4 instead of 2. Why?
Both ratings and comments have multiple rows for paperid = 1. So, joining the tables yields four results, with the following ids:
ratings comments
1 1
1 5
5 1
5 5
Hence, the count is 4. You can fix the count by doing count(distinct comments.id). However, the average is going to be off.
One way to fix this problem is by aggregating ratings and comments in subqueries.
I have this 3 tables:
Users:
user_id|user_nick
1 | a
2 | b
Category:
cat_id|cat_type
1 | a
2 | b
3 | c
4 | d
Meta:
met_id|met_name|met_user|met_type
10 | bla | 1 | 1
11 | blabla | 2 | 2
12 | foo | 1 | 3
13 | blafoo | 2 | 4
14 | foofoo | 1 | 4
15 | foobla | 1 | 4
How can I return something like this ?
user_id|met_type|total
1 | 1 | 1
1 | 2 | 0
1 | 3 | 1
1 | 4 | 2
For just one user and not for all of them.
met_type is a foreign key from Category.
I've tried like this but no success :/
SELECT met_user, met_type, COUNT(*) FROM Meta GROUP BY met_user WHERE met_user = '1'
Query:
SELECT met_user, met_type, count(*)
FROM Meta
WHERE met_user='1'
GROUP BY met_type;
To get empty groups, you can use generateSeries() here:
SELECT m.met_user, g.meta_type, count(m)
FROM generate_series(1, 4) AS g(meta_type)
LEFT OUTER JOIN Meta AS m
ON m.met_user='1'
AND m.met_type=g.meta_type
GROUP BY g.meta_type, m.met_user
ORDER BY g.meta_type;
Check it out! I made an sql fiddle.
I have MySQL tables that look like this
users
user_id | partner_id | name
--------+------------+-----
1 | 2 | aaa
2 | 1 | bbb
3 | 4 | ccc
4 | 3 | ddd
games
game_id | user_id
--------+--------
1 | 1
2 | 1
3 | 2
4 | 3
5 | 4
6 | 4
scores
game_id | level | score | time
--------+-------+-------+-----
1 | 1 | 1 | 10
1 | 2 | 1 | 10
1 | 3 | 1 | 10
2 | 1 | 0 | 20
2 | 2 | 0 | 20
2 | 3 | 0 | 20
3 | 1 | 1 | 30
3 | 2 | 1 | 30
3 | 3 | 1 | 30
4 | 1 | 1 | 2
4 | 2 | 1 | 2
4 | 3 | 1 | 2
5 | 1 | 1 | 5
5 | 2 | 1 | 5
5 | 3 | 1 | 5
6 | 1 | 1 | 3
6 | 2 | 1 | 3
6 | 3 | 0 | 3
And i need to query it so it sums points and time per game, so it looks like this
game_id | user_id | sumPoints | sumTime
--------+---------+-----------+--------
1 | 1 | 3 | 30
2 | 1 | 0 | 60
3 | 2 | 3 | 90
4 | 3 | 3 | 6
5 | 4 | 3 | 15
6 | 4 | 2 | 9
And then i need to get best scores per pair (where it takes better score of one user), so it looks like this:
user1_id | user2_id | sumPoints | sumTime
---------+----------+-----------+--------
3 | 4 | 3 | 6
1 | 2 | 3 | 30
That's the final result. I'd really appreciate if someone could show me how it should looks like as sql query.
I'd like to mention that first part is solved by JW 웃 in this post
Thanks in advance.
Something like this should work (this answers your second query)
SELECT
user_details.user_id,
user_details.partner_id,
score_details.score,
score_details.time
FROM
( SELECT
min(user_id) as user_id,
max(user_id) as partner_id
FROM
users
GROUP BY
user_id + partner_id ) AS user_details
JOIN
( SELECT
scores.game_id ,
games.user_id,
sum(score) score,
sum(time) time,
#row_num := IF(#prev_value=games.user_id,#row_num+1,1) AS row_num,
#prev_value := games.user_id
FROM
scores
inner join games on games.game_id = scores.game_id
inner join users on users.user_id = games.user_id
GROUP BY
scores.game_id
ORDER BY
user_id,
score
) as score_details ON ( score_details.user_id = user_details.user_id AND score_details.row_num = 1)
The first part of JOIN gets the users along with their partners, users appearing first within their pair are displayed first, eg: if there are 2 users with ID 1 and 2 I consider the user_id of user 1 as he appears first within his pair.
The second query is based on "echo_me" answer along with a row_number that specifies the ranking of the scores for each user, the highest score has the rank as 1 for every user.
SQLFIDDLE
Hope this is helpful
try this
select scores.game_id ,games.user_id,sum(score) score, sum(time) time
from scores
inner join games
on games.game_id = scores.game_id
inner join users
on users.user_id = games.user_id
group by scores.game_id
DEMO HERE
for the best score
select users.user_id as user1_id,users.partner_id as user2_id,sum(score) score, sum(time) time
from scores
inner join games
on games.game_id = scores.game_id
inner join users
on users.user_id = games.user_id
group by scores.game_id
order by sum(time) asc limit 1
DEMO HERE
OUTPUT.
USER1_ID USER2_ID SCORE TIME
1 2 3 30
In a last Question, i asked about geting all actions of the last three users from a history table that stores all actions done by users on deferments posts, now what i want is to get the same thing but for each post.
all actions of the last three users for each posts
history table
id | post_id | action | user_id
1 | 5 | 1 | 3
1 | 23 | 2 | 1
2 | 24 | 2 | 6
3 | 34 | 1 | 7
4 | 35 | 1 | 1
5 | 36 | 1 | 1
6 | 23 | 2 | 3
7 | 24 | 2 | 1
8 | 23 | 1 | 4
9 | 24 | 1 | 5
10 | 24 | 1 | 1
11 | 23 | 1 | 2
12 | 23 | 4 | 1
thanks and sorry if it seem to be a duplicate post
This is a query that requires lots of self joins:
select hl.post_id, h.*
from history h join
(select h.*, count(*) as NumLater
from history h join
history h2
on h.post_id = h2.post_id and
h2.id >= h.id
group by h.id
having NumLater <= 3
) hl
on h.user_id = hl.user_id
order by hl.post_id
The inner query does a self join to calculate the number of history entries after each record in the same post. The join then joins this by user_id to the history table. This version does not eliminate duplicates. So, a user could be in the last-three set for two different posts.